/*
 * Copyright © 2005 Novell, Inc.
 *
 * Permission to use, copy, modify, distribute, and sell this software
 * and its documentation for any purpose is hereby granted without
 * fee, provided that the above copyright notice appear in all copies
 * and that both that copyright notice and this permission notice
 * appear in supporting documentation, and that the name of
 * Novell, Inc. not be used in advertising or publicity pertaining to
 * distribution of the software without specific, written prior permission.
 * Novell, Inc. makes no representations about the suitability of this
 * software for any purpose. It is provided "as is" without express or
 * implied warranty.
 *
 * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
 * NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 * Author: David Reveman <davidr@novell.com>
 */

/*
 * Spring model implemented by Kristian Hogsberg.
 */

#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <compiz.h>
#include <X11/Xlib.h>


//************************************************maxamal code
//static int firstMove = 0;
static int borderWidth = 4;//6
static int titleBarHeight = 23;//23
typedef struct ValidWindowExpansion
{
	int x;
	int y;
	int height;
	int width;
	int initialized;
} ValidWindowExpansion;
static const int ARRAYSIZE = 1000;

typedef struct Node {
	Window window;
	int initialized;
} Node;

static int snapCount = 0;
static Display* myDisplay;// = XOpenDisplay(0);
typedef struct Line {
int x1;
int x2;
int y1;
int y2;
double a;
double b;
double c;
double yCoordinateOfIntersection;
double xCoordinateOfIntersection;
int initialized; 
} Line;

//typedef enum {FALSE, TRUE} Boolean;
//static Line allLinesOnScreen[1000];

//static vector<Line> screenEdges;

void getAnUpdatedArrayOfLines(Window, Line[]);
void getAllLinesOfIntersection(Line, Line[], Line[]);
void getListOfWindows(Node[]);
int max(int, int);
int min(int, int);
//Atom getWindowType(Window);
Line calculateLineOfImpact(Line, Line[]);             
void calculateDimensionsGivenHorozontalLineHitFromBottom(int, int, ValidWindowExpansion[], Window);
void calculateDimensionsGivenHorozontalLineHitFromTop(int, int, ValidWindowExpansion[], Window);
void calculateDimensionsGivenVerticalLineHitFromLeft(int, int, ValidWindowExpansion[], Window);
void calculateDimensionsGivenVerticalLineHitFromRight(int, int, ValidWindowExpansion[], Window);
int scanUp(Line line, Line[]);
int scanDown(Line line, Line[]);
int scanLeft(Line line, Line[]);
int scanRight(Line line, Line[]);

//***********************************************

#define WIN_X(w) ((w)->attrib.x - (w)->output.left)
#define WIN_Y(w) ((w)->attrib.y - (w)->output.top)
#define WIN_W(w) ((w)->width + (w)->output.left + (w)->output.right)
#define WIN_H(w) ((w)->height + (w)->output.top + (w)->output.bottom)

#define GRID_WIDTH  4
#define GRID_HEIGHT 4

#define MODEL_MAX_SPRINGS (GRID_WIDTH * GRID_HEIGHT * 2)

#define MASS 15.0f

typedef struct _xy_pair {/*{{{*/
    float x, y;
} Point, Vector;/*}}}*/

#define NorthEdgeMask (1L << 0)
#define SouthEdgeMask (1L << 1)
#define WestEdgeMask  (1L << 2)
#define EastEdgeMask  (1L << 3)

#define WOBBLY_EDGE_DISTANCE_DEFAULT 25.0f
#define WOBBLY_EDGE_DISTANCE_MIN 1.0f
#define WOBBLY_EDGE_DISTANCE_MAX 50.0f
#define WOBBLY_EDGE_DISTANCE_PRECISION 0.5f

#define WOBBLY_EDGE_VELOCITY_DEFAULT 13.0f
#define WOBBLY_EDGE_VELOCITY_MIN 1.0f
#define WOBBLY_EDGE_VELOCITY_MAX 50.0f
#define WOBBLY_EDGE_VELOCITY_PRECISION 0.5f

typedef struct _Edge {/*{{{*/
    float next, prev;

    float start;
    float end;

    float attract;
    float velocity;

    Bool  snapped;
} Edge;/*}}}*/

typedef struct _Object {/*{{{*/
    Vector	 force;
    Point	 position;
    Vector	 velocity;
    float	 theta;
    Bool	 immobile;
    unsigned int edgeMask;
    Edge	 vertEdge;
    Edge	 horzEdge;
} Object;/*}}}*/

typedef struct _Spring {
    Object *a;
    Object *b;
    Vector offset;
} Spring;

#define NORTH 0
#define SOUTH 1
#define WEST  2
#define EAST  3

typedef struct _Model {
    Object	 *objects;
    int		 numObjects;
    Spring	 springs[MODEL_MAX_SPRINGS];
    int		 numSprings;
    Object	 *anchorObject;
    float	 steps;
    Vector	 scale;
    Point	 scaleOrigin;
    Bool	 transformed;
    Point	 topLeft;
    Point	 bottomRight;
    unsigned int edgeMask;
    unsigned int snapCnt[4];
} Model;

#define WOBBLY_FRICTION_DEFAULT    3.0f
#define WOBBLY_FRICTION_MIN        0.1f
#define WOBBLY_FRICTION_MAX       10.0f
#define WOBBLY_FRICTION_PRECISION  0.1f

#define WOBBLY_SPRING_K_DEFAULT    8.0f
#define WOBBLY_SPRING_K_MIN        0.1f
#define WOBBLY_SPRING_K_MAX       10.0f
#define WOBBLY_SPRING_K_PRECISION  0.1f

#define WOBBLY_GRID_RESOLUTION_DEFAULT  24
#define WOBBLY_GRID_RESOLUTION_MIN      1
#define WOBBLY_GRID_RESOLUTION_MAX      64

#define WOBBLY_MIN_GRID_SIZE_DEFAULT  8
#define WOBBLY_MIN_GRID_SIZE_MIN      4
#define WOBBLY_MIN_GRID_SIZE_MAX      128

#define WOBBLY_MAXIMIZE_FRICTION_DEFAULT 0.8f
#define WOBBLY_MAXIMIZE_SPRING_K_DEFAULT 0.3f
#define WOBBLY_MAP_FRICTION_DEFAULT      0.8f
#define WOBBLY_MAP_SPRING_K_DEFAULT      0.3f

#define WOBBLY_URGENT_VELOCITY_DEFAULT   1.0f

#define WOBBLY_RELEASE_DEFAULT          FALSE
#define WOBBLY_DEFAULT_SNAP_DEFAULT     TRUE
#define WOBBLY_URGENT_EFFECT_DEFAULT    FALSE
#define WOBBLY_URGENT_IN_DEFAULT        FALSE
#define WOBBLY_URGENT_UNIFORM_DEFAULT   TRUE

typedef enum {
    WobblyEffectNone = 0,
    WobblyEffectShiver
} WobblyEffect;

static char *effectName[] = {
    N_("None"),
    N_("Shiver")
};

static WobblyEffect effectType[] = {
    WobblyEffectNone,
    WobblyEffectShiver
};

#define NUM_EFFECT (sizeof (effectType) / sizeof (effectType[0]))

#define WOBBLY_MAP_DEFAULT   (effectName[1])
#define WOBBLY_FOCUS_DEFAULT (effectName[0])

static char *mapWinType[] = {
    N_("Splash"),
    N_("DropdownMenu"),
    N_("PopupMenu"),
    N_("Tooltip"),
    N_("Notification"),
    N_("Combo"),
    N_("Dnd"),
    N_("Unknown")
};
#define N_MAP_WIN_TYPE (sizeof (mapWinType) / sizeof (mapWinType[0]))
#define N_FOCUS_WIN_TYPE (0)

static char *moveWinType[] = {
    N_("Toolbar"),
    N_("Menu"),
    N_("Utility"),
    N_("Dialog"),
    N_("ModalDialog"),
    N_("Normal")
};
#define N_MOVE_WIN_TYPE (sizeof (moveWinType) / sizeof (moveWinType[0]))
#define N_GRAB_WIN_TYPE (0)

#define WOBBLY_SNAP_MODIFIERS_DEFAULT ShiftMask

#define WOBBLY_MAXIMIZE_EFFECT_DEFAULT TRUE

static int displayPrivateIndex;

#define WOBBLY_DISPLAY_OPTION_SNAP   0
#define WOBBLY_DISPLAY_OPTION_SHIVER 1
#define WOBBLY_DISPLAY_OPTION_DEFAULT_SNAP      2
#define WOBBLY_DISPLAY_OPTION_NUM    3

typedef struct _WobblyDisplay {
    int		    screenPrivateIndex;
    Atom            wmHintsAtom;
    HandleEventProc handleEvent;

    CompOption opt[WOBBLY_DISPLAY_OPTION_NUM];

    Bool snapping;
} WobblyDisplay;

#define WOBBLY_SCREEN_OPTION_MOVE_FRICTION     0
#define WOBBLY_SCREEN_OPTION_MOVE_SPRING_K     1
#define WOBBLY_SCREEN_OPTION_GRID_RESOLUTION   2
#define WOBBLY_SCREEN_OPTION_MIN_GRID_SIZE     3
#define WOBBLY_SCREEN_OPTION_MAP_EFFECT	       4
#define WOBBLY_SCREEN_OPTION_FOCUS_EFFECT      5
#define WOBBLY_SCREEN_OPTION_MAP_WINDOW_TYPE   6
#define WOBBLY_SCREEN_OPTION_FOCUS_WINDOW_TYPE 7
#define WOBBLY_SCREEN_OPTION_GRAB_WINDOW_TYPE  8
#define WOBBLY_SCREEN_OPTION_MOVE_WINDOW_TYPE  9
#define WOBBLY_SCREEN_OPTION_MAXIMIZE_EFFECT   10
#define WOBBLY_SCREEN_OPTION_MAP_FRICTION      11
#define WOBBLY_SCREEN_OPTION_MAP_SPRING_K      12
#define WOBBLY_SCREEN_OPTION_GRAB_FRICTION     13
#define WOBBLY_SCREEN_OPTION_GRAB_SPRING_K     14
#define WOBBLY_SCREEN_OPTION_FOCUS_FRICTION    15
#define WOBBLY_SCREEN_OPTION_FOCUS_SPRING_K    16
#define WOBBLY_SCREEN_OPTION_MAXIMIZE_FRICTION 17
#define WOBBLY_SCREEN_OPTION_MAXIMIZE_SPRING_K 18
#define WOBBLY_SCREEN_OPTION_BELL_FRICTION     19
#define WOBBLY_SCREEN_OPTION_BELL_SPRING_K     20
#define WOBBLY_SCREEN_OPTION_RELEASE_FRICTION  21
#define WOBBLY_SCREEN_OPTION_RELEASE_SPRING_K  22
#define WOBBLY_SCREEN_OPTION_USE_RELEASE       23
#define WOBBLY_SCREEN_OPTION_URGENT_EFFECT     24
#define WOBBLY_SCREEN_OPTION_URGENT_FRICTION   25
#define WOBBLY_SCREEN_OPTION_URGENT_SPRING_K   26
#define WOBBLY_SCREEN_OPTION_URGENT_VELOCITY   27
#define WOBBLY_SCREEN_OPTION_URGENT_IN         28
#define WOBBLY_SCREEN_OPTION_URGENT_UNIFORM    29
#define WOBBLY_SCREEN_OPTION_EDGE_DISTANCE     30
#define WOBBLY_SCREEN_OPTION_EDGE_VELOCITY     31
#define WOBBLY_SCREEN_OPTION_NUM              32

typedef struct _WobblyScreen {
    int	windowPrivateIndex;

    PreparePaintScreenProc preparePaintScreen;
    DonePaintScreenProc	   donePaintScreen;
    PaintScreenProc	   paintScreen;
    PaintWindowProc	   paintWindow;
    DamageWindowRectProc   damageWindowRect;
    AddWindowGeometryProc  addWindowGeometry;
    DrawWindowGeometryProc drawWindowGeometry;
    SetWindowScaleProc     setWindowScale;

    WindowResizeNotifyProc windowResizeNotify;
    WindowMoveNotifyProc   windowMoveNotify;
    WindowGrabNotifyProc   windowGrabNotify;
    WindowUngrabNotifyProc windowUngrabNotify;

    CompOption opt[WOBBLY_SCREEN_OPTION_NUM];

    Bool wobblyWindows;

    WobblyEffect mapEffect;
    WobblyEffect focusEffect;

    unsigned int mapWMask;
    unsigned int focusWMask;
    unsigned int moveWMask;
    unsigned int grabWMask;

    unsigned int grabMask;
    CompWindow	 *grabWindow;

    float edgeDistance;
    float edgeVelocity;
} WobblyScreen;

#define WobblyInitial  (1L << 0)
#define WobblyForce    (1L << 1)
#define WobblyVelocity (1L << 2)

typedef struct _WobblyWindow {
    Model	 *model;
    int		 wobbly;
    Bool	 grabbed;
    Bool	 velocity;
    unsigned int state;
    float        friction;
    float        spring_k;
} WobblyWindow;

#define GET_WOBBLY_DISPLAY(d)				       \
    ((WobblyDisplay *) (d)->privates[displayPrivateIndex].ptr)

#define WOBBLY_DISPLAY(d)		       \
    WobblyDisplay *wd = GET_WOBBLY_DISPLAY (d)

#define GET_WOBBLY_SCREEN(s, wd)				   \
    ((WobblyScreen *) (s)->privates[(wd)->screenPrivateIndex].ptr)

#define WOBBLY_SCREEN(s)						      \
    WobblyScreen *ws = GET_WOBBLY_SCREEN (s, GET_WOBBLY_DISPLAY (s->display))

#define GET_WOBBLY_WINDOW(w, ws)				   \
    ((WobblyWindow *) (w)->privates[(ws)->windowPrivateIndex].ptr)

#define WOBBLY_WINDOW(w)				         \
    WobblyWindow *ww = GET_WOBBLY_WINDOW  (w,		         \
		       GET_WOBBLY_SCREEN  (w->screen,	         \
		       GET_WOBBLY_DISPLAY (w->screen->display)))

#define NUM_OPTIONS(s) (sizeof ((s)->opt) / sizeof (CompOption))

static CompOption *
wobblyGetScreenOptions (CompScreen *screen,
			int	   *count)
{
    WOBBLY_SCREEN (screen);

    *count = NUM_OPTIONS (ws);
    return ws->opt;
}

static Bool
wobblySetScreenOption (CompScreen      *screen,
		     char	     *name,
		     CompOptionValue *value)
{
    CompOption *o;
    int	       index;

    WOBBLY_SCREEN (screen);

    o = compFindOption (ws->opt, NUM_OPTIONS (ws), name, &index);
    if (!o)
	return FALSE;

    switch (index) {
    /*
    case WOBBLY_SCREEN_OPTION_FRICTION:
    case WOBBLY_SCREEN_OPTION_SPRING_K:
    */
    case WOBBLY_SCREEN_OPTION_MOVE_FRICTION:
    case WOBBLY_SCREEN_OPTION_MOVE_SPRING_K:
    case WOBBLY_SCREEN_OPTION_MAP_FRICTION:
    case WOBBLY_SCREEN_OPTION_MAP_SPRING_K:
    case WOBBLY_SCREEN_OPTION_GRAB_FRICTION:
    case WOBBLY_SCREEN_OPTION_GRAB_SPRING_K:
    case WOBBLY_SCREEN_OPTION_FOCUS_FRICTION:
    case WOBBLY_SCREEN_OPTION_FOCUS_SPRING_K:
    case WOBBLY_SCREEN_OPTION_MAXIMIZE_FRICTION:
    case WOBBLY_SCREEN_OPTION_MAXIMIZE_SPRING_K:
    case WOBBLY_SCREEN_OPTION_BELL_FRICTION:
    case WOBBLY_SCREEN_OPTION_BELL_SPRING_K:
    case WOBBLY_SCREEN_OPTION_RELEASE_FRICTION:
    case WOBBLY_SCREEN_OPTION_RELEASE_SPRING_K:  
    case WOBBLY_SCREEN_OPTION_URGENT_FRICTION:
    case WOBBLY_SCREEN_OPTION_URGENT_SPRING_K:    
    case WOBBLY_SCREEN_OPTION_URGENT_VELOCITY:
            if (compSetFloatOption (o, value))
	    return TRUE;
	break;
    case WOBBLY_SCREEN_OPTION_GRID_RESOLUTION:
	if (compSetIntOption (o, value))
	    return TRUE;
	break;
    case WOBBLY_SCREEN_OPTION_MIN_GRID_SIZE:
	if (compSetIntOption (o, value))
	    return TRUE;
	break;
    case WOBBLY_SCREEN_OPTION_MAP_EFFECT:
	if (compSetStringOption (o, value))
	{
	    int i;

	    for (i = 0; i < NUM_EFFECT; i++)
	    {
		if (strcmp (o->value.s, effectName[i]) == 0)
		{
		    ws->mapEffect = effectType[i];
		    return TRUE;
		}
	    }
	}
	break;
    case WOBBLY_SCREEN_OPTION_FOCUS_EFFECT:
	if (compSetStringOption (o, value))
	{
	    int i;

	    for (i = 0; i < NUM_EFFECT; i++)
	    {
		if (strcmp (o->value.s, effectName[i]) == 0)
		{
		    ws->focusEffect = effectType[i];
		    return TRUE;
		}
	    }
	}
	break;
    case WOBBLY_SCREEN_OPTION_MAP_WINDOW_TYPE:
	if (compSetOptionList (o, value))
	{
	    ws->mapWMask = compWindowTypeMaskFromStringList (&o->value);
	    return TRUE;
	}
	break;
    case WOBBLY_SCREEN_OPTION_FOCUS_WINDOW_TYPE:
	if (compSetOptionList (o, value))
	{
	    ws->focusWMask = compWindowTypeMaskFromStringList (&o->value);
	    return TRUE;
	}
	break;
    case WOBBLY_SCREEN_OPTION_MOVE_WINDOW_TYPE:
	if (compSetOptionList (o, value))
	{
	    ws->moveWMask = compWindowTypeMaskFromStringList (&o->value);
	    return TRUE;
	}
	break;
    case WOBBLY_SCREEN_OPTION_GRAB_WINDOW_TYPE:
	if (compSetOptionList (o, value))
	{
	    ws->grabWMask = compWindowTypeMaskFromStringList (&o->value);
	    return TRUE;
	}
	break;
    case WOBBLY_SCREEN_OPTION_MAXIMIZE_EFFECT:
    case WOBBLY_SCREEN_OPTION_USE_RELEASE:
    case WOBBLY_SCREEN_OPTION_URGENT_EFFECT:
    case WOBBLY_SCREEN_OPTION_URGENT_IN:
    case WOBBLY_SCREEN_OPTION_URGENT_UNIFORM:
	if (compSetBoolOption (o, value))
	    return TRUE;
    break;
    case WOBBLY_SCREEN_OPTION_EDGE_DISTANCE:
       if (compSetFloatOption (o, value))
       {
           ws->edgeDistance = o->value.f;
           return TRUE;
       }
       break;
    case WOBBLY_SCREEN_OPTION_EDGE_VELOCITY:
       if (compSetFloatOption (o, value))
       {
           ws->edgeVelocity = o->value.f;
           return TRUE;
       }
       break;
    default:
	break;
    }

    return FALSE;
}

static void
wobblyScreenInitOptions (WobblyScreen *ws,
			 Display      *display)
{
    //printf("init display");
    fflush(stdout);
    myDisplay = XOpenDisplay(0);
    CompOption *o;
    int	       i;
    
    o = &ws->opt[WOBBLY_SCREEN_OPTION_MAXIMIZE_FRICTION];
    o->name		= "maximize_friction";
    o->shortDesc	= "Maximize Friction";
    o->longDesc		= "Spring Friction for maximize effect";
    o->type		= CompOptionTypeFloat;
    o->value.f		= WOBBLY_MAXIMIZE_FRICTION_DEFAULT;
    o->rest.f.min	= WOBBLY_FRICTION_MIN;
    o->rest.f.max	= WOBBLY_FRICTION_MAX;
    o->rest.f.precision = WOBBLY_FRICTION_PRECISION;

    o = &ws->opt[WOBBLY_SCREEN_OPTION_MAXIMIZE_SPRING_K];
    o->name		= "maximize_spring_k";
    o->shortDesc	= "Maximize Spring K";
    o->longDesc		= "Spring Konstant for maximize effect";
    o->type		= CompOptionTypeFloat;
    o->value.f		= WOBBLY_MAXIMIZE_SPRING_K_DEFAULT;
    o->rest.f.min	= WOBBLY_SPRING_K_MIN;
    o->rest.f.max	= WOBBLY_SPRING_K_MAX;
    o->rest.f.precision = WOBBLY_SPRING_K_PRECISION;

    o = &ws->opt[WOBBLY_SCREEN_OPTION_MOVE_FRICTION];
    o->name		= "move_friction";
    o->shortDesc	= "Friction";
    o->longDesc		= "Spring Friction for move types";
    o->type		= CompOptionTypeFloat;
    o->value.f		= WOBBLY_FRICTION_DEFAULT;
    o->rest.f.min	= WOBBLY_FRICTION_MIN;
    o->rest.f.max	= WOBBLY_FRICTION_MAX;
    o->rest.f.precision = WOBBLY_FRICTION_PRECISION;

    o = &ws->opt[WOBBLY_SCREEN_OPTION_MOVE_SPRING_K];
    o->name		= "move_spring_k";
    o->shortDesc	= "Spring K";
    o->longDesc		= "Spring Konstant for move types";
    o->type		= CompOptionTypeFloat;
    o->value.f		= WOBBLY_SPRING_K_DEFAULT;
    o->rest.f.min	= WOBBLY_SPRING_K_MIN;
    o->rest.f.max	= WOBBLY_SPRING_K_MAX;
    o->rest.f.precision = WOBBLY_SPRING_K_PRECISION;

    o = &ws->opt[WOBBLY_SCREEN_OPTION_MAP_FRICTION];
    o->name		= "map_friction";
    o->shortDesc	= "Friction";
    o->longDesc		= "Spring Friction for map types";
    o->type		= CompOptionTypeFloat;
    o->value.f		= WOBBLY_MAP_FRICTION_DEFAULT;
    o->rest.f.min	= WOBBLY_FRICTION_MIN;
    o->rest.f.max	= WOBBLY_FRICTION_MAX;
    o->rest.f.precision = WOBBLY_FRICTION_PRECISION;

    o = &ws->opt[WOBBLY_SCREEN_OPTION_MAP_SPRING_K];
    o->name		= "map_spring_k";
    o->shortDesc	= "Spring K";
    o->longDesc		= "Spring Konstant for map types";
    o->type		= CompOptionTypeFloat;
    o->value.f		= WOBBLY_MAP_SPRING_K_DEFAULT;
    o->rest.f.min	= WOBBLY_SPRING_K_MIN;
    o->rest.f.max	= WOBBLY_SPRING_K_MAX;
    o->rest.f.precision = WOBBLY_SPRING_K_PRECISION;

    o = &ws->opt[WOBBLY_SCREEN_OPTION_GRAB_FRICTION];
    o->name		= "grab_friction";
    o->shortDesc	= "Friction";
    o->longDesc		= "Spring Friction for grab types";
    o->type		= CompOptionTypeFloat;
    o->value.f		= WOBBLY_FRICTION_DEFAULT;
    o->rest.f.min	= WOBBLY_FRICTION_MIN;
    o->rest.f.max	= WOBBLY_FRICTION_MAX;
    o->rest.f.precision = WOBBLY_FRICTION_PRECISION;

    o = &ws->opt[WOBBLY_SCREEN_OPTION_GRAB_SPRING_K];
    o->name		= "grab_spring_k";
    o->shortDesc	= "Spring K";
    o->longDesc		= "Spring Konstant for grab types";
    o->type		= CompOptionTypeFloat;
    o->value.f		= WOBBLY_SPRING_K_DEFAULT;
    o->rest.f.min	= WOBBLY_SPRING_K_MIN;
    o->rest.f.max	= WOBBLY_SPRING_K_MAX;
    o->rest.f.precision = WOBBLY_SPRING_K_PRECISION;

    o = &ws->opt[WOBBLY_SCREEN_OPTION_FOCUS_FRICTION];
    o->name		= "focus_friction";
    o->shortDesc	= "Friction";
    o->longDesc		= "Spring Friction for focus types";
    o->type		= CompOptionTypeFloat;
    o->value.f		= WOBBLY_FRICTION_DEFAULT;
    o->rest.f.min	= WOBBLY_FRICTION_MIN;
    o->rest.f.max	= WOBBLY_FRICTION_MAX;
    o->rest.f.precision = WOBBLY_FRICTION_PRECISION;

    o = &ws->opt[WOBBLY_SCREEN_OPTION_FOCUS_SPRING_K];
    o->name		= "focus_spring_k";
    o->shortDesc	= "Spring K";
    o->longDesc		= "Spring Konstant for focus types";
    o->type		= CompOptionTypeFloat;
    o->value.f		= WOBBLY_SPRING_K_DEFAULT;
    o->rest.f.min	= WOBBLY_SPRING_K_MIN;
    o->rest.f.max	= WOBBLY_SPRING_K_MAX;
    o->rest.f.precision = WOBBLY_SPRING_K_PRECISION;

    o = &ws->opt[WOBBLY_SCREEN_OPTION_GRID_RESOLUTION];
    o->name	  = "grid_resolution";
    o->shortDesc  = N_("Grid Resolution");
    o->longDesc	  = N_("Vertex Grid Resolution");
    o->type	  = CompOptionTypeInt;
    o->value.i	  = WOBBLY_GRID_RESOLUTION_DEFAULT;
    o->rest.i.min = WOBBLY_GRID_RESOLUTION_MIN;
    o->rest.i.max = WOBBLY_GRID_RESOLUTION_MAX;

    o = &ws->opt[WOBBLY_SCREEN_OPTION_MIN_GRID_SIZE];
    o->name	  = "min_grid_size";
    o->shortDesc  = N_("Minimum Grid Size");
    o->longDesc	  = N_("Minimum Vertex Grid Size");
    o->type	  = CompOptionTypeInt;
    o->value.i	  = WOBBLY_MIN_GRID_SIZE_DEFAULT;
    o->rest.i.min = WOBBLY_MIN_GRID_SIZE_MIN;
    o->rest.i.max = WOBBLY_MIN_GRID_SIZE_MAX;

    o = &ws->opt[WOBBLY_SCREEN_OPTION_MAP_EFFECT];
    o->name	      = "map_effect";
    o->shortDesc      = N_("Map Effect");
    o->longDesc	      = N_("Map Window Effect");
    o->type	      = CompOptionTypeString;
    o->value.s	      = strdup (WOBBLY_MAP_DEFAULT);
    o->rest.s.string  = effectName;
    o->rest.s.nString = NUM_EFFECT;

    o = &ws->opt[WOBBLY_SCREEN_OPTION_FOCUS_EFFECT];
    o->name	      = "focus_effect";
    o->shortDesc      = N_("Focus Effect");
    o->longDesc	      = N_("Focus Window Effect");
    o->type	      = CompOptionTypeString;
    o->value.s	      = strdup (WOBBLY_FOCUS_DEFAULT);
    o->rest.s.string  = effectName;
    o->rest.s.nString = NUM_EFFECT;

    o = &ws->opt[WOBBLY_SCREEN_OPTION_MAP_WINDOW_TYPE];
    o->name	         = "map_window_types";
    o->shortDesc         = N_("Map Window Types");
    o->longDesc	         = N_("Window types that should wobble when mapped");
    o->type	         = CompOptionTypeList;
    o->value.list.type   = CompOptionTypeString;
    o->value.list.nValue = N_MAP_WIN_TYPE;
    o->value.list.value  = malloc (sizeof (CompOptionValue) * N_MAP_WIN_TYPE);
    for (i = 0; i < N_MAP_WIN_TYPE; i++)
	o->value.list.value[i].s = strdup (mapWinType[i]);
    o->rest.s.string     = windowTypeString;
    o->rest.s.nString    = nWindowTypeString;

    ws->mapWMask = compWindowTypeMaskFromStringList (&o->value);

    o = &ws->opt[WOBBLY_SCREEN_OPTION_FOCUS_WINDOW_TYPE];
    o->name	         = "focus_window_types";
    o->shortDesc         = N_("Focus Window Types");
    o->longDesc	         = N_("Window types that should wobble when focused");
    o->type	         = CompOptionTypeList;
    o->value.list.type   = CompOptionTypeString;
    o->value.list.nValue = N_FOCUS_WIN_TYPE;
    o->value.list.value  = NULL;
    o->rest.s.string     = windowTypeString;
    o->rest.s.nString    = nWindowTypeString;

    ws->focusWMask = compWindowTypeMaskFromStringList (&o->value);

    o = &ws->opt[WOBBLY_SCREEN_OPTION_MOVE_WINDOW_TYPE];
    o->name	         = "move_window_types";
    o->shortDesc         = N_("Move Window Types");
    o->longDesc	         = N_("Window types that should wobble when moved");
    o->type	         = CompOptionTypeList;
    o->value.list.type   = CompOptionTypeString;
    o->value.list.nValue = N_MOVE_WIN_TYPE;
    o->value.list.value  = malloc (sizeof (CompOptionValue) * N_MOVE_WIN_TYPE);
    for (i = 0; i < N_MOVE_WIN_TYPE; i++)
	o->value.list.value[i].s = strdup (moveWinType[i]);
    o->rest.s.string     = windowTypeString;
    o->rest.s.nString    = nWindowTypeString;

    ws->moveWMask = compWindowTypeMaskFromStringList (&o->value);

    o = &ws->opt[WOBBLY_SCREEN_OPTION_GRAB_WINDOW_TYPE];
    o->name	         = "grab_window_types";
    o->shortDesc         = N_("Grab Window Types");
    o->longDesc	         = N_("Window types that should wobble when grabbed");
    o->type	         = CompOptionTypeList;
    o->value.list.type   = CompOptionTypeString;
    o->value.list.nValue = N_GRAB_WIN_TYPE;
    o->value.list.value  = NULL;
    o->rest.s.string     = windowTypeString;
    o->rest.s.nString    = nWindowTypeString;

    ws->grabWMask = compWindowTypeMaskFromStringList (&o->value);

    o = &ws->opt[WOBBLY_SCREEN_OPTION_MAXIMIZE_EFFECT];
    o->name	  = "maximize_effect";
    o->shortDesc  = N_("Maximize Effect");
    o->longDesc	  = N_("Wobble effect when maximizing and unmaximizing windows");
    o->type	  = CompOptionTypeBool;
    o->value.b    = WOBBLY_MAXIMIZE_EFFECT_DEFAULT;

    o = &ws->opt[WOBBLY_SCREEN_OPTION_BELL_FRICTION];
    o->name		= "visual_bell_friction";
    o->shortDesc	= "Friction";
    o->longDesc		= "Spring Friction for bell effect";
    o->type		= CompOptionTypeFloat;
    o->value.f		= WOBBLY_FRICTION_DEFAULT;
    o->rest.f.min	= WOBBLY_FRICTION_MIN;
    o->rest.f.max	= WOBBLY_FRICTION_MAX;
    o->rest.f.precision = WOBBLY_FRICTION_PRECISION;

    o = &ws->opt[WOBBLY_SCREEN_OPTION_BELL_SPRING_K];
    o->name		= "visual_bell_spring_k";
    o->shortDesc	= "Spring K";
    o->longDesc		= "Spring Konstant for bell effect";
    o->type		= CompOptionTypeFloat;
    o->value.f		= WOBBLY_SPRING_K_DEFAULT;
    o->rest.f.min	= WOBBLY_SPRING_K_MIN;
    o->rest.f.max	= WOBBLY_SPRING_K_MAX;
    o->rest.f.precision = WOBBLY_SPRING_K_PRECISION;

    o = &ws->opt[WOBBLY_SCREEN_OPTION_USE_RELEASE];
    o->name	  = "release_effect";
    o->shortDesc  = "Release Effect";
    o->longDesc	  = "Use settings for releasing windows";
    o->type	  = CompOptionTypeBool;
    o->value.b    = WOBBLY_RELEASE_DEFAULT;

    o = &ws->opt[WOBBLY_SCREEN_OPTION_RELEASE_FRICTION];
    o->name		= "release_friction";
    o->shortDesc	= "Friction";
    o->longDesc		= "Spring Friction for release effect";
    o->type		= CompOptionTypeFloat;
    o->value.f		= WOBBLY_FRICTION_DEFAULT;
    o->rest.f.min	= WOBBLY_FRICTION_MIN;
    o->rest.f.max	= WOBBLY_FRICTION_MAX;
    o->rest.f.precision = WOBBLY_FRICTION_PRECISION;

    o = &ws->opt[WOBBLY_SCREEN_OPTION_RELEASE_SPRING_K];
    o->name		= "release_spring_k";
    o->shortDesc	= "Spring K";
    o->longDesc		= "Spring Konstant for release effect";
    o->type		= CompOptionTypeFloat;
    o->value.f		= WOBBLY_SPRING_K_DEFAULT;
    o->rest.f.min	= WOBBLY_SPRING_K_MIN;
    o->rest.f.max	= WOBBLY_SPRING_K_MAX;
    o->rest.f.precision = WOBBLY_SPRING_K_PRECISION;


    o = &ws->opt[WOBBLY_SCREEN_OPTION_URGENT_EFFECT];
    o->name	  = "urgent_effect";
    o->shortDesc  = "Use urgent effect";
    o->longDesc	  = "Make urgent windows wobble";
    o->type	  = CompOptionTypeBool;
    o->value.b    = WOBBLY_URGENT_EFFECT_DEFAULT;

    o = &ws->opt[WOBBLY_SCREEN_OPTION_URGENT_FRICTION];
    o->name		= "urgent_friction";
    o->shortDesc	= "Friction";
    o->longDesc		= "Spring Friction for urgent effect";
    o->type		= CompOptionTypeFloat;
    o->value.f		= WOBBLY_FRICTION_DEFAULT;
    o->rest.f.min	= WOBBLY_FRICTION_MIN;
    o->rest.f.max	= WOBBLY_FRICTION_MAX;
    o->rest.f.precision = WOBBLY_FRICTION_PRECISION;

    o = &ws->opt[WOBBLY_SCREEN_OPTION_URGENT_SPRING_K];
    o->name		= "urgent_spring_k";
    o->shortDesc	= "Spring K";
    o->longDesc		= "Spring Konstant for urgent effect";
    o->type		= CompOptionTypeFloat;
    o->value.f		= WOBBLY_SPRING_K_DEFAULT;
    o->rest.f.min	= WOBBLY_SPRING_K_MIN;
    o->rest.f.max	= WOBBLY_SPRING_K_MAX;
    o->rest.f.precision = WOBBLY_SPRING_K_PRECISION;

    o = &ws->opt[WOBBLY_SCREEN_OPTION_URGENT_VELOCITY];
    o->name		= "urgent_velocity";
    o->shortDesc	= "Velocity";
    o->longDesc		= "Window velocity for urgent effect";
    o->type		= CompOptionTypeFloat;
    o->value.f		= WOBBLY_URGENT_VELOCITY_DEFAULT;
    o->rest.f.min	= WOBBLY_SPRING_K_MIN;
    o->rest.f.max	= WOBBLY_SPRING_K_MAX;
    o->rest.f.precision = WOBBLY_SPRING_K_PRECISION;

    o = &ws->opt[WOBBLY_SCREEN_OPTION_URGENT_IN];
    o->name	  = "urgent_effect_in";
    o->shortDesc  = "Urgent effect in";
    o->longDesc	  = "Make urgent windows wobble inward";
    o->type	  = CompOptionTypeBool;
    o->value.b    =  WOBBLY_URGENT_IN_DEFAULT;

    o = &ws->opt[WOBBLY_SCREEN_OPTION_URGENT_UNIFORM];
    o->name	  = "urgent_effect_uniform";
    o->shortDesc  = "Urgent effect uniform";
    o->longDesc	  = "Make urgent windows wobble uniformly";
    o->type	  = CompOptionTypeBool;
    o->value.b    = WOBBLY_URGENT_UNIFORM_DEFAULT;

    o = &ws->opt[WOBBLY_SCREEN_OPTION_EDGE_DISTANCE];
    o->name            = "edge_distance";
    o->shortDesc       = "Edge snapping distance";
    o->longDesc                = "Edge snapping distance";
    o->type            = CompOptionTypeFloat;
    o->value.f         = WOBBLY_EDGE_DISTANCE_DEFAULT;
    o->rest.f.min      = WOBBLY_EDGE_DISTANCE_MIN;
    o->rest.f.max      = WOBBLY_EDGE_DISTANCE_MAX;
    o->rest.f.precision = WOBBLY_EDGE_DISTANCE_PRECISION;

    o = &ws->opt[WOBBLY_SCREEN_OPTION_EDGE_VELOCITY];
    o->name            = "edge_velocity";
    o->shortDesc       = "Edge snapping velocity";
    o->longDesc                = "Edge snapping velocity";
    o->type            = CompOptionTypeFloat;
    o->value.f         = WOBBLY_EDGE_VELOCITY_DEFAULT;
    o->rest.f.min      = WOBBLY_EDGE_VELOCITY_MIN;
    o->rest.f.max      = WOBBLY_EDGE_VELOCITY_MAX;
    o->rest.f.precision = WOBBLY_EDGE_VELOCITY_PRECISION;

}

static void
findNextWestEdge (CompWindow *w,
		  Object     *object)
{
	
    int v, v1, v2;
    int s, start;
    int e, end;
    int x;
    int i;

    start = -65535.0f;
    end   =  65535.0f;

    v1 = -65535.0f;
    v2 =  65535.0f;

    x = object->position.x + w->output.left - w->input.left;

    if (x >= w->screen->workArea.x)
    {
	CompWindow *p;

	if ( w->screen->useXinerama )
	{
	    for ( i = 1; i <= w->screen->headsCount; i++ )
	    {
		s = screenGetHeadAreaY ( w->screen, i );
		e = screenGetHeadAreaY ( w->screen, i ) + screenGetHeadAreaHeight ( w->screen, i );

		if ( s > object->position.y )
		{
		    if ( s < end )
			end = s;
		}
		else if ( e < object->position.y )
		{
		    if ( e > start )
			start = e;
		}
		else
		{
		    if ( s > start )
			start = s;
    
		    if ( e < end )
			end = e;
    
		    v = screenGetHeadAreaX ( w->screen, i );
		    if ( v <= x )
		    {
			if ( v > v1 )
			    v1 = v;
		    }
		    else
		    {
			if ( v < v2 )
			    v2 = v;
		    }
		}
	    }
	}
	else
	{
	    v1 = w->screen->workArea.x;
	}

	for (p = w->screen->windows; p; p = p->next)
	{
	    if (p->invisible || w == p || p->type != CompWindowTypeNormalMask)
		continue;

	    s = p->attrib.y - p->output.top;
	    e = p->attrib.y + p->height + p->output.bottom;

	    if (s > object->position.y)
	    {
		if (s < end)
		    end = s;
	    }
	    else if (e < object->position.y)
	    {
		if (e > start)
		    start = e;
	    }
	    else
	    {
		if (s > start)
		    start = s;

		if (e < end)
		    end = e;

		v = p->attrib.x + p->width + p->input.right;
		if (v <= x)
		{
		    if (v > v1)
			v1 = v;
		}
		else
		{
		    if (v < v2)
			v2 = v;
		}
	    }
	}
    }
    else
    {
	v2 = w->screen->workArea.x;
    }

    v1 = v1 - w->output.left + w->input.left;
    v2 = v2 - w->output.left + w->input.left;

    if (v1 != (int) object->vertEdge.next)
	object->vertEdge.snapped = FALSE;

    object->vertEdge.start = start;
    object->vertEdge.end   = end;

    object->vertEdge.next = v1;
    object->vertEdge.prev = v2;

    WOBBLY_SCREEN (w->screen);

    object->vertEdge.attract  = v1 + ws->edgeDistance;
    object->vertEdge.velocity = ws->edgeVelocity;
}

static void
findNextEastEdge (CompWindow *w,
		  Object     *object)
{

    int v, v1, v2;
    int s, start;
    int e, end;
    int x;
    int i;

    start = -65535.0f;
    end   =  65535.0f;

    v1 =  65535.0f;
    v2 = -65535.0f;

    x = object->position.x - w->output.right + w->input.right;

    if (x <= w->screen->workArea.x + w->screen->workArea.width)
    {
	CompWindow *p;

	if ( w->screen->useXinerama )
	{
	    for ( i = 1; i <= w->screen->headsCount; i++ )
	    {
		s = screenGetHeadAreaY ( w->screen, i );
		e = screenGetHeadAreaY ( w->screen, i ) + screenGetHeadAreaHeight ( w->screen, i );

		if ( s > object->position.y )
		{
		    if ( s < end )
			end = s;
		}
		else if ( e < object->position.y )
		{
		    if ( e > start )
			start = e;
		}
		else
		{
		    if ( s > start )
			start = s;
    
		    if ( e < end )
			end = e;
    
		    v = screenGetHeadAreaX ( w->screen, i ) + screenGetHeadAreaWidth ( w->screen, i );
		    if ( v >= x )
		    {
			if ( v < v1 )
			    v1 = v;
		    }
		    else
		    {
			if ( v > v2 )
			    v2 = v;
		    }
		}
	    }
	}
	else
	{
	    v1 = w->screen->workArea.x + w->screen->workArea.width;
	}

	for (p = w->screen->windows; p; p = p->next)
	{
	    if (p->invisible || w == p || p->type != CompWindowTypeNormalMask)
		continue;

	    s = p->attrib.y - p->output.top;
	    e = p->attrib.y + p->height + p->output.bottom;

	    if (s > object->position.y)
	    {
		if (s < end)
		    end = s;
	    }
	    else if (e < object->position.y)
	    {
		if (e > start)
		    start = e;
	    }
	    else
	    {
		if (s > start)
		    start = s;

		if (e < end)
		    end = e;

		v = p->attrib.x - p->input.left;
		if (v >= x)
		{
		    if (v < v1)
			v1 = v;
		}
		else
		{
		    if (v > v2)
			v2 = v;
		}
	    }
	}
    }
    else
    {
	v2 = w->screen->workArea.x + w->screen->workArea.width;
    }

    v1 = v1 + w->output.right - w->input.right;
    v2 = v2 + w->output.right - w->input.right;

    if (v1 != (int) object->vertEdge.next)
	object->vertEdge.snapped = FALSE;

    object->vertEdge.start = start;
    object->vertEdge.end   = end;

    object->vertEdge.next = v1;
    object->vertEdge.prev = v2;

    WOBBLY_SCREEN (w->screen);

    object->vertEdge.attract  = v1 - ws->edgeDistance;
    object->vertEdge.velocity = ws->edgeVelocity;
}

static void
findNextNorthEdge (CompWindow *w,
		   Object     *object)
{
    int v, v1, v2;
    int s, start;
    int e, end;
    int y;
    int i;

    start = -65535.0f;
    end   =  65535.0f;

    v1 = -65535.0f;
    v2 =  65535.0f;

    y = object->position.y + w->output.top - w->input.top;

    if (y >= w->screen->workArea.y)
    {
	CompWindow *p;

	if ( w->screen->useXinerama )
	{
	    for ( i = 1; i <= w->screen->headsCount; i++ )
	    {
		s = screenGetHeadAreaX ( w->screen, i );
		e = screenGetHeadAreaX ( w->screen, i ) + screenGetHeadAreaWidth ( w->screen, i );

		if ( s > object->position.x )
		{
		    if ( s < end )
			end = s;
		}
		else if ( e < object->position.x )
		{
		    if ( e > start )
			start = e;
		}
		else
		{
		    if ( s > start )
			start = s;

		    if ( e < end )
			end = e;

		    v = screenGetHeadAreaY ( w->screen, i );
		    if ( v <= y )
		    {
                        if ( v > v1 )
                            v1 = v;
		    }
		    else
		    {
			if ( v < v2 )
			    v2 = v;
		    }
		}
	    }
	}
	else
	{
	    v1 = w->screen->workArea.y;
	}

	for (p = w->screen->windows; p; p = p->next)
	{
	    if (p->invisible || w == p || p->type != CompWindowTypeNormalMask)
		continue;

	    s = p->attrib.x - p->output.left;
	    e = p->attrib.x + p->width + p->output.right;

	    if (s > object->position.x)
	    {
		if (s < end)
		    end = s;
	    }
	    else if (e < object->position.x)
	    {
		if (e > start)
		    start = e;
	    }
	    else
	    {
		if (s > start)
		    start = s;

		if (e < end)
		    end = e;

		v = p->attrib.y + p->height + p->input.bottom;
		if (v <= y)
		{
		    if (v > v1)
			v1 = v;
		}
		else
		{
		    if (v < v2)
			v2 = v;
		}
	    }
	}
    }
    else
    {
	v2 = w->screen->workArea.y;
    }

    v1 = v1 - w->output.top + w->input.top;
    v2 = v2 - w->output.top + w->input.top;

    if (v1 != (int) object->horzEdge.next)
	object->horzEdge.snapped = FALSE;

    object->horzEdge.start = start;
    object->horzEdge.end   = end;

    object->horzEdge.next = v1;
    object->horzEdge.prev = v2;

    WOBBLY_SCREEN(w->screen);

    object->horzEdge.attract  = v1 + ws->edgeDistance;
    object->horzEdge.velocity = ws->edgeVelocity;
}

static void
findNextSouthEdge (CompWindow *w,
		   Object     *object)
{//printf("4");
    int v, v1, v2;
    int s, start;
    int e, end;
    int y;
    int i;

    start = -65535.0f;
    end   =  65535.0f;

    v1 =  65535.0f;
    v2 = -65535.0f;

    y = object->position.y - w->output.bottom + w->input.bottom;

    if (y <= w->screen->workArea.y + w->screen->workArea.height)
    {
	CompWindow *p;

	if ( w->screen->useXinerama )
	{
	    for ( i = 1; i <= w->screen->headsCount; i++ )
	    {
		s = screenGetHeadAreaX ( w->screen, i );
		e = screenGetHeadAreaX ( w->screen, i ) + screenGetHeadAreaWidth ( w->screen, i );

		if ( s > object->position.x )
		{
		    if ( s < end )
			end = s;
		}
		else if ( e < object->position.x )
		{
		    if ( e > start )
			start = e;
		}
		else
		{
		    if ( s > start )
			start = s;

		    if ( e < end )
			end = e;

		    v = screenGetHeadAreaY ( w->screen, i ) + screenGetHeadAreaHeight ( w->screen, i );
		    if ( v >= y )
		    {
                        if ( v < v1 )
                            v1 = v;
		    }
		    else
		    {
			if ( v > v2 )
			    v2 = v;
		    }
		}
	    }
	}
	else
	{
	    v1 = w->screen->workArea.y + w->screen->workArea.height;
	}

	for (p = w->screen->windows; p; p = p->next)
	{
	    if (p->invisible || w == p || p->type != CompWindowTypeNormalMask)
		continue;

	    s = p->attrib.x - p->output.left;
	    e = p->attrib.x + p->width + p->output.right;

	    if (s > object->position.x)
	    {
		if (s < end)
		    end = s;
	    }
	    else if (e < object->position.x)
	    {
		if (e > start)
		    start = e;
	    }
	    else
	    {
		if (s > start)
		    start = s;

		if (e < end)
		    end = e;

		v = p->attrib.y - p->input.top;
		if (v >= y)
		{
		    if (v < v1)
			v1 = v;
		}
		else
		{
		    if (v > v2)
			v2 = v;
		}
	    }
	}
    }
    else
    {
	v2 = w->screen->workArea.y + w->screen->workArea.height;
    }

    v1 = v1 + w->output.bottom - w->input.bottom;
    v2 = v2 + w->output.bottom - w->input.bottom;

    if (v1 != (int) object->horzEdge.next)
	object->horzEdge.snapped = FALSE;

    object->horzEdge.start = start;
    object->horzEdge.end   = end;

    object->horzEdge.next = v1;
    object->horzEdge.prev = v2;

    WOBBLY_SCREEN(w->screen);

    object->horzEdge.attract  = v1 - ws->edgeDistance;
    object->horzEdge.velocity = ws->edgeVelocity;
}

static void
objectInit (Object *object,
	    float  positionX,
	    float  positionY,
	    float  velocityX,
	    float  velocityY)
{
//printf("6");
    object->force.x = 0;
    object->force.y = 0;

    object->position.x = positionX;
    object->position.y = positionY;

    object->velocity.x = velocityX;
    object->velocity.y = velocityY;

    object->theta    = 0;
    object->immobile = FALSE;

    object->edgeMask = 0;

    object->vertEdge.snapped = FALSE;
    object->horzEdge.snapped = FALSE;

    object->vertEdge.next = 0.0f;
    object->horzEdge.next = 0.0f;
}

static void
springInit (Spring *spring,
	    Object *a,
	    Object *b,
	    float  offsetX,
	    float  offsetY)
{
    spring->a	     = a;
    spring->b	     = b;
    spring->offset.x = offsetX;
    spring->offset.y = offsetY;
}

static void
modelCalcBounds (Model *model)
{
//printf("calc");
    int i;

    model->topLeft.x	 = MAXSHORT;
    model->topLeft.y	 = MAXSHORT;
    model->bottomRight.x = MINSHORT;
    model->bottomRight.y = MINSHORT;

    for (i = 0; i < model->numObjects; i++)
    {
	if (model->objects[i].position.x < model->topLeft.x)
	    model->topLeft.x = model->objects[i].position.x;
	else if (model->objects[i].position.x > model->bottomRight.x)
	    model->bottomRight.x = model->objects[i].position.x;

	if (model->objects[i].position.y < model->topLeft.y)
	    model->topLeft.y = model->objects[i].position.y;
	else if (model->objects[i].position.y > model->bottomRight.y)
	    model->bottomRight.y = model->objects[i].position.y;
    }
}

static void
modelAddSpring (Model  *model,
		Object *a,
		Object *b,
		float  offsetX,
		float  offsetY)
{//printf("8");
    Spring *spring;

    spring = &model->springs[model->numSprings];
    model->numSprings++;

    springInit (spring, a, b, offsetX, offsetY);
}

static void
modelSetMiddleAnchor (Model *model,
		      int   x,
		      int   y,
		      int   width,
		      int   height)
{
//printf("an");
    float gx, gy, x0, y0;

    x0 = model->scaleOrigin.x;
    y0 = model->scaleOrigin.y;

    gx = ((GRID_WIDTH  - 1) / 2 * width)  / (float) (GRID_WIDTH  - 1);
    gy = ((GRID_HEIGHT - 1) / 2 * height) / (float) (GRID_HEIGHT - 1);

    if (model->anchorObject)
	model->anchorObject->immobile = FALSE;

    model->anchorObject = &model->objects[GRID_WIDTH *
					  ((GRID_HEIGHT - 1) / 2) +
					  (GRID_WIDTH - 1) / 2];
    model->anchorObject->position.x = x + (gx - x0) * model->scale.x + x0;
    model->anchorObject->position.y = y + (gy - y0) * model->scale.y + y0;

    model->anchorObject->immobile = TRUE;
}

static void
modelAddEdgeAnchors (Model *model,
		     int   x,
		     int   y,
		     int   width,
		     int   height)
{//printf("9");
    Object *o;
    float  x0, y0;

    x0 = model->scaleOrigin.x;
    y0 = model->scaleOrigin.y;

    o = &model->objects[0];
    o->position.x = x + (0      - x0) * model->scale.x + x0;
    o->position.y = y + (0      - y0) * model->scale.y + y0;
    o->immobile = TRUE;

    o = &model->objects[GRID_WIDTH - 1];
    o->position.x = x + (width  - x0) * model->scale.x + x0;
    o->position.y = y + (0      - y0) * model->scale.y + y0;
    o->immobile = TRUE;

    o = &model->objects[GRID_WIDTH * (GRID_HEIGHT - 1)];
    o->position.x = x + (0      - x0) * model->scale.x + x0;
    o->position.y = y + (height - y0) * model->scale.y + y0;
    o->immobile = TRUE;

    o = &model->objects[model->numObjects - 1];
    o->position.x = x + (width  - x0) * model->scale.x + x0;
    o->position.y = y + (height - y0) * model->scale.y + y0;
    o->immobile = TRUE;

    if (!model->anchorObject)
	model->anchorObject = &model->objects[0];
}

static void
modelRemoveEdgeAnchors (Model *model,
			int   x,
			int   y,
			int   width,
			int   height)
{
    Object *o;
    float  x0, y0;

    x0 = model->scaleOrigin.x;
    y0 = model->scaleOrigin.y;

    o = &model->objects[0];
    o->position.x = x + (0      - x0) * model->scale.x + x0;
    o->position.y = y + (0      - y0) * model->scale.y + y0;
    if (o != model->anchorObject)
	o->immobile = FALSE;

    o = &model->objects[GRID_WIDTH - 1];
    o->position.x = x + (width  - x0) * model->scale.x + x0;
    o->position.y = y + (0      - y0) * model->scale.y + y0;
    if (o != model->anchorObject)
	o->immobile = FALSE;

    o = &model->objects[GRID_WIDTH * (GRID_HEIGHT - 1)];
    o->position.x = x + (0      - x0) * model->scale.x + x0;
    o->position.y = y + (height - y0) * model->scale.y + y0;
    if (o != model->anchorObject)
	o->immobile = FALSE;

    o = &model->objects[model->numObjects - 1];
    o->position.x = x + (width  - x0) * model->scale.x + x0;
    o->position.y = y + (height - y0) * model->scale.y + y0;
    if (o != model->anchorObject)
	o->immobile = FALSE;
}

static void
modelAdjustObjectPosition (Model  *model,
			   Object *object,
			   int    x,
			   int    y,
			   int    width,
			   int    height)
{//printf( " m ");
//fflush(stdout);
    Object *o;
    float  x0, y0;
    int	   gridX, gridY, i = 0;

    x0 = model->scaleOrigin.x;
    y0 = model->scaleOrigin.y;

    for (gridY = 0; gridY < GRID_HEIGHT; gridY++)
    {
	for (gridX = 0; gridX < GRID_WIDTH; gridX++)
	{
	    o = &model->objects[i];
	    if (o == object)
	    {
		o->position.x = x +
		    (((gridX * width) / (GRID_WIDTH - 1)) - x0) *
		    model->scale.x + x0;
		o->position.y = y +
		    (((gridY * height) / (GRID_HEIGHT - 1)) - y0) *
		    model->scale.y + y0;

		return;
	    }

	    i++;
	}
    }
}

static void
modelInitObjects (Model *model,
		  int	x,
		  int   y,
		  int	width,
		  int	height)
{
    int	  gridX, gridY, i = 0;
    float gw, gh, x0, y0;

    x0 = model->scaleOrigin.x;
    y0 = model->scaleOrigin.y;

    gw = GRID_WIDTH  - 1;
    gh = GRID_HEIGHT - 1;

    for (gridY = 0; gridY < GRID_HEIGHT; gridY++)
    {
	for (gridX = 0; gridX < GRID_WIDTH; gridX++)
	{
	    objectInit (&model->objects[i],
			x + (((gridX * width)  / gw) - x0) *
			model->scale.x + x0,
			y + (((gridY * height) / gh) - y0) *
			model->scale.y + y0,
			0, 0);
	    i++;
	}
    }

    modelSetMiddleAnchor (model, x, y, width, height);
}

static void
modelUpdateSnapping (CompWindow *window,
		     Model      *model)
{
    unsigned int edgeMask, gridMask, mask;
    int		 gridX, gridY, i = 0;

    edgeMask = model->edgeMask;

    if (model->snapCnt[NORTH])
	edgeMask &= ~SouthEdgeMask;
    else if (model->snapCnt[SOUTH])
	edgeMask &= ~NorthEdgeMask;

    if (model->snapCnt[WEST])
	edgeMask &= ~EastEdgeMask;
    else if (model->snapCnt[EAST])
	edgeMask &= ~WestEdgeMask;

    for (gridY = 0; gridY < GRID_HEIGHT; gridY++)
    {
	if (gridY == 0)
	    gridMask = edgeMask & NorthEdgeMask;
	else if (gridY == GRID_HEIGHT - 1)
	    gridMask = edgeMask & SouthEdgeMask;
	else
	    gridMask = 0;

	for (gridX = 0; gridX < GRID_WIDTH; gridX++)
	{
	    mask = gridMask;

	    if (gridX == 0)
		mask |= edgeMask & WestEdgeMask;
	    else if (gridX == GRID_WIDTH - 1)
		mask |= edgeMask & EastEdgeMask;

	    if (mask != model->objects[i].edgeMask)
	    {
		model->objects[i].edgeMask = mask;

		if (mask & WestEdgeMask)
		{
		    if (!model->objects[i].vertEdge.snapped)
			findNextWestEdge (window, &model->objects[i]);
		}
		else if (mask & EastEdgeMask)
		{
		    if (!model->objects[i].vertEdge.snapped)
			findNextEastEdge (window, &model->objects[i]);
		}
		else
		    model->objects[i].vertEdge.snapped = FALSE;

		if (mask & NorthEdgeMask)
		{
		    if (!model->objects[i].horzEdge.snapped)
			findNextNorthEdge (window, &model->objects[i]);
		}
		else if (mask & SouthEdgeMask)
		{
		    if (!model->objects[i].horzEdge.snapped)
			findNextSouthEdge (window, &model->objects[i]);
		}
		else
		    model->objects[i].horzEdge.snapped = FALSE;
	    }

	    i++;
	}
    }
}

static void
modelReduceEdgeEscapeVelocity (Model *model)
{
    int	gridX, gridY, i = 0;

    for (gridY = 0; gridY < GRID_HEIGHT; gridY++)
    {
	for (gridX = 0; gridX < GRID_WIDTH; gridX++)
	{
	    if (model->objects[i].vertEdge.snapped)
		model->objects[i].vertEdge.velocity *= drand48 () * 0.25f;

	    if (model->objects[i].horzEdge.snapped)
		model->objects[i].horzEdge.velocity *= drand48 () * 0.25f;

	    i++;
	}
    }
}

static Bool
modelDisableSnapping (CompWindow *window,
		      Model      *model)
{
//printf("disable");
    int	 gridX, gridY, i = 0;
    Bool snapped = FALSE;

    for (gridY = 0; gridY < GRID_HEIGHT; gridY++)
    {
	for (gridX = 0; gridX < GRID_WIDTH; gridX++)
	{
	    if (model->objects[i].vertEdge.snapped ||
		model->objects[i].horzEdge.snapped)
		snapped = TRUE;

	    model->objects[i].vertEdge.snapped = FALSE;
	    model->objects[i].horzEdge.snapped = FALSE;

	    model->objects[i].edgeMask = 0;

	    i++;
	}
    }

    memset (model->snapCnt, 0, sizeof (model->snapCnt));

    return snapped;
}

static void
modelAdjustObjectsForShiver (Model *model,
			     int   x,
			     int   y,
			     int   width,
			     int   height)
{
    int   gridX, gridY, i = 0;
    float vX, vY;
    float scale;
    float w, h;

    w = (float) width  * model->scale.x;
    h = (float) height * model->scale.y;

    for (gridY = 0; gridY < GRID_HEIGHT; gridY++)
    {
	for (gridX = 0; gridX < GRID_WIDTH; gridX++)
	{
	    if (!model->objects[i].immobile)
	    {
		vX = model->objects[i].position.x - (x + w / 2);
		vY = model->objects[i].position.y - (y + h / 2);

		vX /= w;
		vY /= h;

		scale = ((float) rand () * 7.5f) / RAND_MAX;

		model->objects[i].velocity.x += vX * scale;
		model->objects[i].velocity.y += vY * scale;
	    }

	    i++;
	}
    }
}

static void
modelInitSprings (Model *model,
		  int   x,
		  int   y,
		  int   width,
		  int   height)
{
    int   gridX, gridY, i = 0;
    float hpad, vpad;

    model->numSprings = 0;

    hpad = ((float) width  * model->scale.x) / (GRID_WIDTH  - 1);
    vpad = ((float) height * model->scale.y) / (GRID_HEIGHT - 1);

    for (gridY = 0; gridY < GRID_HEIGHT; gridY++)
    {
	for (gridX = 0; gridX < GRID_WIDTH; gridX++)
	{
	    if (gridX > 0)
		modelAddSpring (model,
				&model->objects[i - 1],
				&model->objects[i],
				hpad, 0);

	    if (gridY > 0)
		modelAddSpring (model,
				&model->objects[i - GRID_WIDTH],
				&model->objects[i],
				0, vpad);

	    i++;
	}
    }
}

static void
modelMove (Model *model,
	   float tx,
	   float ty)
{//printf(" move ");
 
    int i;

    for (i = 0; i < model->numObjects; i++)
    {
	model->objects[i].position.x += tx;
	model->objects[i].position.y += ty;
    }
}

static Model *
createModel (int	  x,
	     int	  y,
	     int	  width,
	     int	  height,
	     unsigned int edgeMask)
{
    Model *model;

    model = malloc (sizeof (Model));
    if (!model)
	return 0;

    model->numObjects = GRID_WIDTH * GRID_HEIGHT;
    model->objects = malloc (sizeof (Object) * model->numObjects);
    if (!model->objects)
	return 0;

    model->anchorObject = 0;
    model->numSprings = 0;

    model->steps = 0;

    model->scale.x = 1.0f;
    model->scale.y = 1.0f;

    model->scaleOrigin.x = 0.0f;
    model->scaleOrigin.y = 0.0f;

    model->transformed = FALSE;

    memset (model->snapCnt, 0, sizeof (model->snapCnt));

    model->edgeMask = edgeMask;

    modelInitObjects (model, x, y, width, height);
    modelInitSprings (model, x, y, width, height);

    modelCalcBounds (model);

    return model;
}

static void
objectApplyForce (Object *object,
		  float  fx,
		  float  fy)
{


//printf(" %f %f ", object->vertEdge.snapped, object->position.y);
    object->force.x += fx;
    object->force.y += fy;
}

static void
springExertForces (Spring *spring,
		   float  k)
{//printf("E");
    Vector da, db;
    Vector a, b;

    a = spring->a->position;
    b = spring->b->position;

    da.x = 0.5f * (b.x - a.x - spring->offset.x);
    da.y = 0.5f * (b.y - a.y - spring->offset.y);

    db.x = 0.5f * (a.x - b.x + spring->offset.x);
    db.y = 0.5f * (a.y - b.y + spring->offset.y);

    objectApplyForce (spring->a, k * da.x, k * da.y);
    objectApplyForce (spring->b, k * db.x, k * db.y);
}

static Bool
objectReleaseWestEdge (CompWindow *w,
		       Model	  *model,
		       Object	  *object)
{//printf("16");
    if (fabs (object->velocity.x) > object->vertEdge.velocity)
    {
	object->position.x += object->velocity.x * 2.0f;

	model->snapCnt[WEST]--;

	object->vertEdge.snapped = FALSE;
	object->edgeMask = 0;

	modelUpdateSnapping (w, model);

	return TRUE;
    }

    object->velocity.x = 0.0f;

    return FALSE;
}

static Bool
objectReleaseEastEdge (CompWindow *w,
		       Model	  *model,
		       Object	  *object)
{//printf("17");
    if (fabs (object->velocity.x) > object->vertEdge.velocity)
    {
	object->position.x += object->velocity.x * 2.0f;

	model->snapCnt[EAST]--;

	object->vertEdge.snapped = FALSE;
	object->edgeMask = 0;

	modelUpdateSnapping (w, model);

	return TRUE;
    }

    object->velocity.x = 0.0f;

    return FALSE;
}

static Bool
objectReleaseNorthEdge (CompWindow *w,
			Model	   *model,
			Object	   *object)
{
    if (fabs (object->velocity.y) > object->horzEdge.velocity)
    {
	object->position.y += object->velocity.y * 2.0f;

	model->snapCnt[NORTH]--;

	object->horzEdge.snapped = FALSE;
	object->edgeMask = 0;

	modelUpdateSnapping (w, model);

	return TRUE;
    }

    object->velocity.y = 0.0f;

    return FALSE;
}

static Bool
objectReleaseSouthEdge (CompWindow *w,
			Model	   *model,
			Object	   *object)
{
//
    if (fabs (object->velocity.y) > object->horzEdge.velocity)
    {
	object->position.y += object->velocity.y * 2.0f;

	model->snapCnt[SOUTH]--;

	object->horzEdge.snapped = FALSE;
	object->edgeMask = 0;

	modelUpdateSnapping (w, model);

	return TRUE;
    }

    object->velocity.y = 0.0f;

    return FALSE;
}

static float
modelStepObject (CompWindow *window,
		 Model	    *model,
		 Object	    *object,
		 float	    friction,
		 float	    *force)
{

    object->theta += 0.05f;

    if (object->immobile)
    {

	object->velocity.x = 0.0f;
	object->velocity.y = 0.0f;

	object->force.x = 0.0f;
	object->force.y = 0.0f;

	*force = 0.0f;

	return 0.0f;
    }
    else
    {
	object->force.x -= friction * object->velocity.x;
	object->force.y -= friction * object->velocity.y;

	object->velocity.x += object->force.x / MASS;
	object->velocity.y += object->force.y / MASS;

	if (object->edgeMask)
	{
		
	    if (object->edgeMask & WestEdgeMask)
	    {
		if (object->position.y < object->vertEdge.start ||
		    object->position.y > object->vertEdge.end)
		    findNextWestEdge (window, object);

		if (object->vertEdge.snapped == FALSE ||
		    objectReleaseWestEdge (window, model, object))
		{
		    object->position.x += object->velocity.x;
			
		    if (object->velocity.x < 0.0f &&
			object->position.x < object->vertEdge.attract)
		    {
			
			
			if (object->position.x < object->vertEdge.next)
			{				
			    object->vertEdge.snapped = TRUE;
			    object->position.x = object->vertEdge.next;
			    object->velocity.x = 0.0f;
//**************************************************************maximal resize code			    
			    Window root_return;
        	            Window child_return;
        		    int root_x_return;
        		    int root_y_return;
        	            int win_x_return;
        		    int win_y_return;
        		    unsigned int mask_return;
			    XQueryPointer(myDisplay, DefaultRootWindow(myDisplay), &root_return, &child_return,
      	 						&root_x_return, &root_y_return, &win_x_return, &win_y_return, &mask_return); 
			    //firstMove = 0; 
      	 		    if((mask_return & Button1Mask) == FALSE )
			    {
				if(snapCount == 3)
				{
					//convert from float to int??
					XWindowAttributes win_attr;			
					XGetWindowAttributes(myDisplay, DefaultRootWindow(myDisplay), &win_attr);
					int rightSideOfScreen = win_attr.x + win_attr.width;
					int bottomSideOfScreen = win_attr.y + win_attr.height;
					int xHitCoordinate = object->vertEdge.next + 9;					
					float midPoint = model->bottomRight.y - ((model->bottomRight.y - model->topLeft.y) / 2 );
					int yHitCoordinate = midPoint;
					if(yHitCoordinate < 1) 
					{
						yHitCoordinate = 1;
					}
					if(xHitCoordinate < 1)
					{
						xHitCoordinate = 1;
					}
					
					//printf(" st %f en %f \n", model->topLeft.y, model->bottomRight.y);
				//	printf(" mid %f \n", midPoint);
				//	printf(" west y %f x %f \n", model->topLeft.y, object->vertEdge.next);
				//	printf(" awest y %i x %i \n", yHitCoordinate, xHitCoordinate);
					fflush(stdout);				
					
			    		
		    			ValidWindowExpansion validWindowExpansions[ARRAYSIZE];					
					calculateDimensionsGivenVerticalLineHitFromRight(xHitCoordinate, yHitCoordinate, validWindowExpansions, window->id);

					ValidWindowExpansion validWindowExpansion;
					validWindowExpansion.initialized = 0;
					int i = 0;
					while(validWindowExpansions[i].initialized)
					{
						if(validWindowExpansions[i].width > 20 && validWindowExpansions[i].height > 20 && 
					           validWindowExpansions[i].width < rightSideOfScreen && validWindowExpansions[i].height < bottomSideOfScreen)
						{
							validWindowExpansion = validWindowExpansions[i];
							break;
						
						}
						i++;
					}									
					if(validWindowExpansion.initialized == 1)
					{
						for(i = 0;i < 600; i++)
						{						
							XMoveResizeWindow(myDisplay, window->id, 
							  validWindowExpansion.x + borderWidth + 2, 
				            		  validWindowExpansion.y + titleBarHeight + 2, 
				             	          validWindowExpansion.width - 2 * borderWidth + 2, 
				              	          validWindowExpansion.height - titleBarHeight - borderWidth + 2);				
						}	
						for(i = 0;i < 600; i++)
						{						
							XMoveResizeWindow(myDisplay, window->id - 2, 
							  validWindowExpansion.x + borderWidth - 2, 
				            		  validWindowExpansion.y + titleBarHeight, 
				             	          validWindowExpansion.width - 2 * borderWidth - 2, 
				              	          validWindowExpansion.height - titleBarHeight - borderWidth - 2);				
						}
						for(i = 0;i < 600; i++)
						{						
							XMoveResizeWindow(myDisplay, window->id, 
							  validWindowExpansion.x + borderWidth, 
				            		  validWindowExpansion.y + titleBarHeight, 
				             	          validWindowExpansion.width - 2 * borderWidth, 
				              	          validWindowExpansion.height - titleBarHeight - borderWidth);				
						}				                  
					}				                  
				
			    }

			snapCount += 1;
			snapCount %= 4;

			}
		    
//************************************************************************
			    model->snapCnt[WEST]++;

			    modelUpdateSnapping (window, model);
			}
			else
			{
			    object->velocity.x -=
				object->vertEdge.attract - object->position.x;
			}
		    }

		    if (object->position.x > object->vertEdge.prev)
			{

			findNextWestEdge (window, object);
			}
		}
	    }
	    else if (object->edgeMask & EastEdgeMask)
	    {
		if (object->position.y < object->vertEdge.start ||
		    object->position.y > object->vertEdge.end)
		    findNextEastEdge (window, object);

		if (object->vertEdge.snapped == FALSE ||
		    objectReleaseEastEdge (window, model, object))
		{
		    object->position.x += object->velocity.x;

		    if (object->velocity.x > 0.0f &&
			object->position.x > object->vertEdge.attract)
		    {
			if (object->position.x > object->vertEdge.next)
			{
			    object->vertEdge.snapped = TRUE;
			    object->position.x = object->vertEdge.next;
			    object->velocity.x = 0.0f;
//**************************************************************maximal resize code			    
			    Window root_return;
        	            Window child_return;
        		    int root_x_return;
        		    int root_y_return;
        	            int win_x_return;
        		    int win_y_return;
        		    unsigned int mask_return;
			    XQueryPointer(myDisplay, DefaultRootWindow(myDisplay), &root_return, &child_return,
      	 						&root_x_return, &root_y_return, &win_x_return, &win_y_return, &mask_return); 
			    
      	 		    if((mask_return & Button1Mask) == FALSE )
			    {	
				if(snapCount == 3)
				{
					XWindowAttributes win_attr;			
					XGetWindowAttributes(myDisplay, DefaultRootWindow(myDisplay), &win_attr);
					int rightSideOfScreen = win_attr.x + win_attr.width;
					int bottomSideOfScreen = win_attr.y + win_attr.height;
					float midPoint = model->bottomRight.y - ((model->bottomRight.y - model->topLeft.y) / 2 );
					int xHitCoordinate = object->vertEdge.next - 12;//object->vertEdge.next - 12;
					int yHitCoordinate = midPoint;
					if(yHitCoordinate > bottomSideOfScreen - 1) 
					{
						yHitCoordinate = bottomSideOfScreen - 1;
					}
					if(xHitCoordinate > rightSideOfScreen - 1)
					{
						xHitCoordinate = rightSideOfScreen - 1;
					}
					//printf(" st %f en %f \n", model->topLeft.y, model->bottomRight.y);
					//printf(" east y %f x %f \n", model->bottomRight.y, object->vertEdge.next); 
					//printf(" aeast y %i x %i \n", yHitCoordinate, xHitCoordinate);
					fflush(stdout);
									
					
			    		
		    			ValidWindowExpansion validWindowExpansions[ARRAYSIZE];					
					calculateDimensionsGivenVerticalLineHitFromLeft(xHitCoordinate, yHitCoordinate, validWindowExpansions, window->id);

					ValidWindowExpansion validWindowExpansion;
					validWindowExpansion.initialized = 0;
					int i = 0;
					while(validWindowExpansions[i].initialized)
					{
						if(validWindowExpansions[i].width > 20 && validWindowExpansions[i].height > 20 && 
					           validWindowExpansions[i].width < rightSideOfScreen && validWindowExpansions[i].height < bottomSideOfScreen)
						{
							validWindowExpansion = validWindowExpansions[i];
							break;
						
						}
						i++;
					}									
					if(validWindowExpansion.initialized == 1)
					{
					//printf(" x %i y %i ", validWindowExpansion.x, validWindowExpansion.y);
						for(i = 0;i < 600; i++)
						{						
							XMoveResizeWindow(myDisplay, window->id, 
							  validWindowExpansion.x + borderWidth + 2, 
				            		  validWindowExpansion.y + titleBarHeight + 2, 
				             	          validWindowExpansion.width - 2 * borderWidth + 2, 
				              	          validWindowExpansion.height - titleBarHeight - borderWidth + 2);				
						}	
						for(i = 0;i < 600; i++)
						{						
							XMoveResizeWindow(myDisplay, window->id - 2, 
							  validWindowExpansion.x + borderWidth - 2, 
				            		  validWindowExpansion.y + titleBarHeight, 
				             	          validWindowExpansion.width - 2 * borderWidth - 2, 
				              	          validWindowExpansion.height - titleBarHeight - borderWidth - 2);				
						}
						for(i = 0;i < 600; i++)
						{						
							XMoveResizeWindow(myDisplay, window->id, 
							  validWindowExpansion.x + borderWidth, 
				            		  validWindowExpansion.y + titleBarHeight, 
				             	          validWindowExpansion.width - 2 * borderWidth, 
				              	          validWindowExpansion.height - titleBarHeight - borderWidth);				
						}					                  
					}		
				
			    }

			snapCount += 1;
			snapCount %= 4;

			}
		    
//************************************************************************
			    model->snapCnt[EAST]++;

			    modelUpdateSnapping (window, model);
			}
			else
			{
			    object->velocity.x =
				object->position.x - object->vertEdge.attract;
			}
		    }

		    if (object->position.x < object->vertEdge.prev)
			findNextEastEdge (window, object);
		}
	    }
	    else
		object->position.x += object->velocity.x;

	    if (object->edgeMask & NorthEdgeMask)
	    {
		if (object->position.x < object->horzEdge.start ||
		    object->position.x > object->horzEdge.end)
		
		    findNextNorthEdge (window, object);

		if (object->horzEdge.snapped == FALSE ||
		    objectReleaseNorthEdge (window, model, object))
		{
		    object->position.y += object->velocity.y;

		    if (object->velocity.y < 0.0f &&
			object->position.y < object->horzEdge.attract)
		    {
			if (object->position.y < object->horzEdge.next)
			{
			    object->horzEdge.snapped = TRUE;
			    object->position.y = object->horzEdge.next;
			    object->velocity.y = 0.0f;
//**************************************************************maximal resize code			    
			    Window root_return;
        	            Window child_return;
        		    int root_x_return;
        		    int root_y_return;
        	            int win_x_return;
        		    int win_y_return;
        		    unsigned int mask_return;
			    XQueryPointer(myDisplay, DefaultRootWindow(myDisplay), &root_return, &child_return,
      	 						&root_x_return, &root_y_return, &win_x_return, &win_y_return, &mask_return); 
			    
      	 		    if((mask_return & Button1Mask) == FALSE )
			    {
				if(snapCount == 3)
				{	
					//add checks to make sure hitpoint is outside of screen	
					XWindowAttributes win_attr;			
					XGetWindowAttributes(myDisplay, DefaultRootWindow(myDisplay), &win_attr);
					int rightSideOfScreen = win_attr.x + win_attr.width;
					int bottomSideOfScreen = win_attr.y + win_attr.height;		
					float midPoint = model->bottomRight.x - ((model->bottomRight.x - model->topLeft.x) / 2 );		
					int xHitCoordinate = midPoint;					
					int yHitCoordinate = object->horzEdge.next + 7;
					if(yHitCoordinate < 1) 
					{
						yHitCoordinate = 1;
					}
					if(xHitCoordinate < 1)
					{
						xHitCoordinate = 1;
					}
					//nprintf(" north y %f x %f \n", object->horzEdge.next, model->topLeft.x); 
				//	printf( "midpoint %f \n", midPoint);
					//printf(" anorth y %i x %i \n", yHitCoordinate, xHitCoordinate);
					fflush(stdout);
					
		    			ValidWindowExpansion validWindowExpansions[ARRAYSIZE];					
					calculateDimensionsGivenHorozontalLineHitFromBottom(xHitCoordinate, yHitCoordinate, validWindowExpansions, window->id);

					ValidWindowExpansion validWindowExpansion;
					validWindowExpansion.initialized = 0;
					int i = 0;
					while(validWindowExpansions[i].initialized)
					{
						if(validWindowExpansions[i].width > 20 && validWindowExpansions[i].height > 20 && 
					           validWindowExpansions[i].width < rightSideOfScreen && validWindowExpansions[i].height < bottomSideOfScreen)
						{
							validWindowExpansion = validWindowExpansions[i];
							break;
						
						}
						i++;
					}									
					if(validWindowExpansion.initialized == 1)
					{
						for(i = 0;i < 600; i++)
						{						
							XMoveResizeWindow(myDisplay, window->id, 
							  validWindowExpansion.x + borderWidth + 2, 
				            		  validWindowExpansion.y + titleBarHeight + 2, 
				             	          validWindowExpansion.width - 2 * borderWidth + 2, 
				              	          validWindowExpansion.height - titleBarHeight - borderWidth + 2);				
						}	
						for(i = 0;i < 600; i++)
						{						
							XMoveResizeWindow(myDisplay, window->id - 2, 
							  validWindowExpansion.x + borderWidth - 2, 
				            		  validWindowExpansion.y + titleBarHeight, 
				             	          validWindowExpansion.width - 2 * borderWidth - 2, 
				              	          validWindowExpansion.height - titleBarHeight - borderWidth - 2);				
						}
						for(i = 0;i < 600; i++)
						{						
							XMoveResizeWindow(myDisplay, window->id, 
							  validWindowExpansion.x + borderWidth, 
				            		  validWindowExpansion.y + titleBarHeight, 
				             	          validWindowExpansion.width - 2 * borderWidth, 
				              	          validWindowExpansion.height - titleBarHeight - borderWidth);				
						}				                  
					}			                  
				
			    }

			snapCount += 1;
			snapCount %= 4;

			}
		    
//************************************************************************
			    model->snapCnt[NORTH]++;

			    modelUpdateSnapping (window, model);
			}
			else
			{
			    object->velocity.y -=
				object->horzEdge.attract - object->position.y;
			}
		    }

		    if (object->position.y > object->horzEdge.prev)
			findNextNorthEdge (window, object);
		}
	    }
	    else if (object->edgeMask & SouthEdgeMask)
	    {
		if (object->position.x < object->horzEdge.start ||
		    object->position.x > object->horzEdge.end)
		    findNextSouthEdge (window, object);

		if (object->horzEdge.snapped == FALSE ||
		    objectReleaseSouthEdge (window, model, object))
		{
		    object->position.y += object->velocity.y;

		    if (object->velocity.y > 0.0f &&
			object->position.y > object->horzEdge.attract)
		    {
			if (object->position.y > object->horzEdge.next)
			{
			    object->horzEdge.snapped = TRUE;
			    object->position.y = object->horzEdge.next;
			    object->velocity.y = 0.0f;
//**************************************************************maximal resize code			    
			    Window root_return;
        	            Window child_return;
        		    int root_x_return;
        		    int root_y_return;
        	            int win_x_return;
        		    int win_y_return;
        		    unsigned int mask_return;
			    XQueryPointer(myDisplay, DefaultRootWindow(myDisplay), &root_return, &child_return,
      	 						&root_x_return, &root_y_return, &win_x_return, &win_y_return, &mask_return); 
			    
      	 		    if((mask_return & Button1Mask) == FALSE )
			    {	
				if(snapCount == 3)
				{
					//convert from float to int??					
					XWindowAttributes win_attr;			
					XGetWindowAttributes(myDisplay, DefaultRootWindow(myDisplay), &win_attr);
					int rightSideOfScreen = win_attr.x + win_attr.width;
					int bottomSideOfScreen = win_attr.y + win_attr.height;
					float midPoint = model->bottomRight.x - ((model->bottomRight.x - model->topLeft.x) / 2 );						
					int xHitCoordinate = midPoint;//model->bottomRight.x - 30;
					int yHitCoordinate = object->horzEdge.next;
					if(yHitCoordinate > bottomSideOfScreen - 1) 
					{
						yHitCoordinate = bottomSideOfScreen - 1;
					}
					if(xHitCoordinate > rightSideOfScreen - 1)
					{
						xHitCoordinate = rightSideOfScreen - 1;
					}
					//printf(" south y %f x %f \n", object->horzEdge.next, model->bottomRight.x); 
					//printf(" asouth y %i x %i \n", yHitCoordinate, xHitCoordinate);
					fflush(stdout);
				
		    			ValidWindowExpansion validWindowExpansions[ARRAYSIZE];				
					calculateDimensionsGivenHorozontalLineHitFromTop(xHitCoordinate, yHitCoordinate, validWindowExpansions, window->id);

					ValidWindowExpansion validWindowExpansion;
					validWindowExpansion.initialized = 0;
	                                int i = 0;
					while(validWindowExpansions[i].initialized)
					{
						if(validWindowExpansions[i].width > 20 && validWindowExpansions[i].height > 20 && 
					           validWindowExpansions[i].width < rightSideOfScreen && validWindowExpansions[i].height < bottomSideOfScreen)
						{
							validWindowExpansion = validWindowExpansions[i];
							break;
						
						}
						i++;
					}						
									
					if(validWindowExpansion.initialized == 1)
					{
						//printf(" x %i y %i ", validWindowExpansion.x, validWindowExpansion.y);
						for(i = 0;i < 600; i++)
						{						
							XMoveResizeWindow(myDisplay, window->id, 
							  validWindowExpansion.x + borderWidth + 2, 
				            		  validWindowExpansion.y + titleBarHeight + 2, 
				             	          validWindowExpansion.width - 2 * borderWidth + 2, 
				              	          validWindowExpansion.height - titleBarHeight - borderWidth + 2);				
						}	
						for(i = 0;i < 600; i++)
						{						
							XMoveResizeWindow(myDisplay, window->id - 2, 
							  validWindowExpansion.x + borderWidth - 2, 
				            		  validWindowExpansion.y + titleBarHeight, 
				             	          validWindowExpansion.width - 2 * borderWidth - 2, 
				              	          validWindowExpansion.height - titleBarHeight - borderWidth - 2);				
						}
						for(i = 0;i < 600; i++)
						{						
							XMoveResizeWindow(myDisplay, window->id, 
							  validWindowExpansion.x + borderWidth, 
				            		  validWindowExpansion.y + titleBarHeight, 
				             	          validWindowExpansion.width - 2 * borderWidth, 
				              	          validWindowExpansion.height - titleBarHeight - borderWidth);				
						}					                  
					}
				
			    }

			snapCount += 1;
			snapCount %= 4;

			}
		    
//************************************************************************
			    model->snapCnt[SOUTH]++;

			    modelUpdateSnapping (window, model);
			}
			else
			{
			    object->velocity.y =
				object->position.y - object->horzEdge.attract;
			}
		    }

		    if (object->position.y < object->horzEdge.prev)
			findNextSouthEdge (window, object);
		}
	    }
	    else
		object->position.y += object->velocity.y;
	}
	else
	{
	    object->position.x += object->velocity.x;
	    object->position.y += object->velocity.y;
	}

	*force = fabs (object->force.x) + fabs (object->force.y);

	object->force.x = 0.0f;
	object->force.y = 0.0f;


	return fabs (object->velocity.x) + fabs (object->velocity.y);
    }
}

static int
modelStep (CompWindow *window,
	   Model      *model,
	   float      friction,
	   float      k,
	   float      time)
{

//**************************************maximal
   /*printf(" step ");
   fflush(stdout);

   Window root_return;
   Window child_return;
   int root_x_return;
   int root_y_return;
   int win_x_return;
   int win_y_return;
   unsigned int mask_return;
   XQueryPointer(myDisplay, DefaultRootWindow(myDisplay), &root_return, &child_return,
      	 	&root_x_return, &root_y_return, &win_x_return, &win_y_return, &mask_return); 
			    
   if(mask_return & Button3Mask)// && firstMove == 0)
   {
	//firstMove = 1;
	printf("here");
	fflush(stdout);
   	XMoveResizeWindow(myDisplay, window->id, 
							  root_x_return - 100, 
				            		  root_y_return - 100,
				             	          200, 200);	
     //XResizeWindow(myDisplay, window->id, 200, 200);
	model->anchorObject->position.x = root_x_return + 30;
	model->anchorObject->position.y = root_y_return + 30;
   }*/
   ///*************************************
			   
    int   i, j, steps, wobbly = 0;
    float velocitySum = 0.0f;
    float force, forceSum = 0.0f;

    model->steps += time / 15.0f;
    steps = floor (model->steps);
    model->steps -= steps;

    if (!steps)
	return TRUE;

    for (j = 0; j < steps; j++)
    {
	for (i = 0; i < model->numSprings; i++)
	    springExertForces (&model->springs[i], k);

	for (i = 0; i < model->numObjects; i++)
	{
	    velocitySum += modelStepObject (window,
					    model,
					    &model->objects[i],
					    friction,
					    &force);
	    forceSum += force;
	}
	//printf("me");
    }

    modelCalcBounds (model);

    if (velocitySum > 0.5f)
	wobbly |= WobblyVelocity;

    if (forceSum > 20.0f)
	wobbly |= WobblyForce;
    
    return wobbly;
}

static void
bezierPatchEvaluate (Model *model,
		     float u,
		     float v,
		     float *patchX,
		     float *patchY)
{
//printf("22");
    float coeffsU[4], coeffsV[4];
    float x, y;
    int   i, j;

    coeffsU[0] = (1 - u) * (1 - u) * (1 - u);
    coeffsU[1] = 3 * u * (1 - u) * (1 - u);
    coeffsU[2] = 3 * u * u * (1 - u);
    coeffsU[3] = u * u * u;

    coeffsV[0] = (1 - v) * (1 - v) * (1 - v);
    coeffsV[1] = 3 * v * (1 - v) * (1 - v);
    coeffsV[2] = 3 * v * v * (1 - v);
    coeffsV[3] = v * v * v;

    x = y = 0.0f;

    for (i = 0; i < 4; i++)
    {
	for (j = 0; j < 4; j++)
	{
	    x += coeffsU[i] * coeffsV[j] *
		model->objects[j * GRID_WIDTH + i].position.x;
	    y += coeffsU[i] * coeffsV[j] *
		model->objects[j * GRID_WIDTH + i].position.y;
	}
    }

    *patchX = x;
    *patchY = y;
}

static Bool
wobblyEnsureModel (CompWindow *w)
{
//printf("23");
    WOBBLY_WINDOW (w);

    if (!ww->model)
    {
	unsigned int edgeMask = 0;

	if (w->type & CompWindowTypeNormalMask)
	    edgeMask = WestEdgeMask | EastEdgeMask | NorthEdgeMask |
		SouthEdgeMask;

	ww->model = createModel (WIN_X (w), WIN_Y (w), WIN_W (w), WIN_H (w),
				 edgeMask);
	if (!ww->model)
	    return FALSE;
    }

    return TRUE;
}

static float
objectDistance (Object *object,
		float  x,
		float  y)
{
//printf("24");
    float dx, dy;

    dx = object->position.x - x;
    dy = object->position.y - y;

    return sqrt (dx * dx + dy * dy);
}

static Object *
modelFindNearestObject (Model *model,
			float x,
			float y)
{//printf("25");
    Object *object = &model->objects[0];
    float  distance, minDistance = 0.0;
    int    i;

    for (i = 0; i < model->numObjects; i++)
    {
	distance = objectDistance (&model->objects[i], x, y);
	if (i == 0 || distance < minDistance)
	{
	    minDistance = distance;
	    object = &model->objects[i];
	}
    }

    return object;
}

static Bool
isWobblyWin (CompWindow *w)
{
    WOBBLY_WINDOW (w);

    if (ww->model)
	return TRUE;

    /* avoid tiny windows */
    if (w->width == 1 && w->height == 1)
	return FALSE;

    /* avoid fullscreen windows */
    if (w->attrib.x <= 0 &&
	w->attrib.y <= 0 &&
	w->attrib.x + w->width >= w->screen->width &&
	w->attrib.y + w->height >= w->screen->height)
	return FALSE;

    return TRUE;
}

static void
wobblyPreparePaintScreen (CompScreen *s,
			  int	     msSinceLastPaint)
{
    WobblyWindow *ww;
    CompWindow   *w;

    WOBBLY_SCREEN (s);

    if (ws->wobblyWindows & (WobblyInitial | WobblyVelocity))
    {
	REGION region;
	Point  topLeft, bottomRight;
	float  friction, springK;
	Model  *model;

	region.rects = &region.extents;
	region.numRects = region.size = 1;

	ws->wobblyWindows = 0;
	for (w = s->windows; w; w = w->next)
	{
	    ww = GET_WOBBLY_WINDOW (w, ws);

            friction = ww->friction;
            springK  = ww->spring_k;

	    if (ww->wobbly)
	    {
		if (ww->wobbly & (WobblyInitial | WobblyVelocity))
		{
		    model = ww->model;
      
		    topLeft     = model->topLeft;
		    bottomRight = model->bottomRight;

		    ww->wobbly = modelStep (w, model, friction, springK,
					    (ww->wobbly & WobblyVelocity) ?
					    msSinceLastPaint :
					    s->redrawTime);
		   // printf(" step ");
		    //fflush(stdout);
	

		    if ((ww->state & MAXIMIZE_STATE) && ww->grabbed)
			ww->wobbly |= WobblyForce;

		    if (ww->wobbly)
		    {
			/* snapped to more than one edge, we have to reduce
			   edge escape velocity until only one edge is snapped */
			if (ww->wobbly == WobblyForce && !ww->grabbed)
			{
			    modelReduceEdgeEscapeVelocity (ww->model);
			    ww->wobbly |= WobblyInitial;
			}
		    }
		    else if (!ww->model->transformed)
		    {
			ww->model = 0;
			//printf("moving");
			moveWindow (w,
				    model->topLeft.x + w->output.left -
				    w->attrib.x,
				    model->topLeft.y + w->output.top -
				    w->attrib.y,
				    TRUE, TRUE);

			ww->model = model;

			syncWindowPosition (w);
		    }

		    if (!(s->damageMask & COMP_SCREEN_DAMAGE_ALL_MASK))
		    {
			if (ww->wobbly)
			{
			    if (ww->model->topLeft.x < topLeft.x)
				topLeft.x = ww->model->topLeft.x;
			    if (ww->model->topLeft.y < topLeft.y)
				topLeft.y = ww->model->topLeft.y;
			    if (ww->model->bottomRight.x > bottomRight.x)
				bottomRight.x = ww->model->bottomRight.x;
			    if (ww->model->bottomRight.y > bottomRight.y)
				bottomRight.y = ww->model->bottomRight.y;
			}
			else
			    addWindowDamage (w);

			region.extents.x1 = topLeft.x;
			region.extents.y1 = topLeft.y;
			region.extents.x2 = bottomRight.x + 0.5f;
			region.extents.y2 = bottomRight.y + 0.5f;

			damageScreenRegion (s, &region);
		    }
		}
 
		ws->wobblyWindows |= ww->wobbly;
	    }	
	}
       
    }
   // printf(" doned ");
//	fflush(stdout);
    UNWRAP (ws, s, preparePaintScreen);
    (*s->preparePaintScreen) (s, msSinceLastPaint);
    WRAP (ws, s, preparePaintScreen, wobblyPreparePaintScreen);
}

static void
wobblyDonePaintScreen (CompScreen *s)
{
    WOBBLY_SCREEN (s);

    if (ws->wobblyWindows & (WobblyVelocity | WobblyInitial))
	damagePendingOnScreen (s);

    UNWRAP (ws, s, donePaintScreen);
    (*s->donePaintScreen) (s);
    WRAP (ws, s, donePaintScreen, wobblyDonePaintScreen);
}

static void
wobblyAddWindowGeometry (CompWindow *w,
			 CompMatrix *matrix,
			 int	    nMatrix,
			 Region     region,
			 Region     clip)
{
//printf("26");
    WOBBLY_WINDOW (w);
    WOBBLY_SCREEN (w->screen);

    if (ww->wobbly)
    {
	BoxPtr   pClip;
	int      nClip, nVertices, nIndices;
	GLushort *i;
	GLfloat  *v;
	int      x1, y1, x2, y2;
	float    width, height;
	float    deformedX, deformedY;
	int      x, y, iw, ih, wx, wy;
	int      vSize, it;
	int      gridW, gridH;
	Bool     rect = TRUE;

	for (it = 0; it < nMatrix; it++)
	{
	    if (matrix[it].xy != 0.0f && matrix[it].yx != 0.0f)
	    {
		rect = FALSE;
		break;
	    }
	}

	wx     = WIN_X (w);
	wy     = WIN_Y (w);
	width  = WIN_W (w);
	height = WIN_H (w);

	gridW = width / ws->opt[WOBBLY_SCREEN_OPTION_GRID_RESOLUTION].value.i;
	if (gridW < ws->opt[WOBBLY_SCREEN_OPTION_MIN_GRID_SIZE].value.i)
	    gridW = ws->opt[WOBBLY_SCREEN_OPTION_MIN_GRID_SIZE].value.i;

	gridH = height / ws->opt[WOBBLY_SCREEN_OPTION_GRID_RESOLUTION].value.i;
	if (gridH < ws->opt[WOBBLY_SCREEN_OPTION_MIN_GRID_SIZE].value.i)
	    gridH = ws->opt[WOBBLY_SCREEN_OPTION_MIN_GRID_SIZE].value.i;

	nClip = region->numRects;
	pClip = region->rects;

	w->texUnits = nMatrix;

	vSize = 2 + nMatrix * 2;

	nVertices = w->vCount;
	nIndices  = w->vCount;

	v = w->vertices + (nVertices * vSize);
	i = w->indices  + nIndices;

	while (nClip--)
	{
	    x1 = pClip->x1;
	    y1 = pClip->y1;
	    x2 = pClip->x2;
	    y2 = pClip->y2;

	    iw = ((x2 - x1 - 1) / gridW) + 1;
	    ih = ((y2 - y1 - 1) / gridH) + 1;

	    if (nIndices + (iw * ih * 4) > w->indexSize)
	    {
		if (!moreWindowIndices (w, nIndices + (iw * ih * 4)))
		    return;

		i = w->indices + nIndices;
	    }

	    iw++;
	    ih++;

	    for (y = 0; y < ih - 1; y++)
	    {
		for (x = 0; x < iw - 1; x++)
		{
		    *i++ = nVertices + iw * (y + 1) + x;
		    *i++ = nVertices + iw * (y + 1) + x + 1;
		    *i++ = nVertices + iw * y + x + 1;
		    *i++ = nVertices + iw * y + x;

		    nIndices += 4;
		}
	    }

	    if (((nVertices + iw * ih) * vSize) > w->vertexSize)
	    {
		if (!moreWindowVertices (w, (nVertices + iw * ih) * vSize))
		    return;

		v = w->vertices + (nVertices * vSize);
	    }

	    for (y = y1;; y += gridH)
	    {
		if (y > y2)
		    y = y2;

		for (x = x1;; x += gridW)
		{
		    if (x > x2)
			x = x2;

		    bezierPatchEvaluate (ww->model,
					 (x - wx) / width,
					 (y - wy) / height,
					 &deformedX,
					 &deformedY);

		    if (rect)
		    {
			for (it = 0; it < nMatrix; it++)
			{
			    *v++ = COMP_TEX_COORD_X (&matrix[it], x);
			    *v++ = COMP_TEX_COORD_Y (&matrix[it], y);
			}
		    }
		    else
		    {
			for (it = 0; it < nMatrix; it++)
			{
			    *v++ = COMP_TEX_COORD_XY (&matrix[it], x, y);
			    *v++ = COMP_TEX_COORD_YX (&matrix[it], x, y);
			}
		    }

		    *v++ = deformedX;
		    *v++ = deformedY;

		    nVertices++;

		    if (x == x2)
			break;
		}

		if (y == y2)
		    break;
	    }

	    pClip++;
	}

	w->vCount = nIndices;
    }
    else
    {
	UNWRAP (ws, w->screen, addWindowGeometry);
	(*w->screen->addWindowGeometry) (w, matrix, nMatrix, region, clip);
	WRAP (ws, w->screen, addWindowGeometry, wobblyAddWindowGeometry);
    }
}

static void
wobblyDrawWindowGeometry (CompWindow *w)
{
    WOBBLY_WINDOW (w);

    if (ww->wobbly)
    {
	int     texUnit = w->texUnits;
	int     currentTexUnit = 0;
	int     stride = (1 + texUnit) * 2;
	GLfloat *vertices = w->vertices + (stride - 2);

	stride *= sizeof (GLfloat);

	glVertexPointer (2, GL_FLOAT, stride, vertices);

	while (texUnit--)
	{
	    if (texUnit != currentTexUnit)
	    {
		w->screen->clientActiveTexture (GL_TEXTURE0_ARB + texUnit);
		glEnableClientState (GL_TEXTURE_COORD_ARRAY);
		currentTexUnit = texUnit;
	    }
	    vertices -= 2;
	    glTexCoordPointer (2, GL_FLOAT, stride, vertices);
	}

	glDrawElements (GL_QUADS, w->vCount, GL_UNSIGNED_SHORT, w->indices);

	/* disable all texture coordinate arrays except 0 */
	texUnit = w->texUnits;
	if (texUnit > 1)
	{
	    while (--texUnit)
	    {
		(*w->screen->clientActiveTexture) (GL_TEXTURE0_ARB + texUnit);
		glDisableClientState (GL_TEXTURE_COORD_ARRAY);
	    }

	    (*w->screen->clientActiveTexture) (GL_TEXTURE0_ARB);
	}
    }
    else
    {
	WOBBLY_SCREEN (w->screen);

	UNWRAP (ws, w->screen, drawWindowGeometry);
	(*w->screen->drawWindowGeometry) (w);
	WRAP (ws, w->screen, drawWindowGeometry, wobblyDrawWindowGeometry);
    }
}

static Bool
wobblyPaintWindow (CompWindow		   *w,
		   const WindowPaintAttrib *attrib,
		   Region		   region,
		   unsigned int		   mask)
{
    Bool status;

    WOBBLY_SCREEN (w->screen);
    WOBBLY_WINDOW (w);

    if (ww->wobbly)
    {
	WindowPaintAttrib wAttrib = *attrib;

	if (mask & PAINT_WINDOW_SOLID_MASK)
	    return FALSE;

	mask |= PAINT_WINDOW_TRANSFORMED_MASK;

	wAttrib.xScale = 1.0f;
	wAttrib.yScale = 1.0f;

	UNWRAP (ws, w->screen, paintWindow);
	status = (*w->screen->paintWindow) (w, &wAttrib, region, mask);
	WRAP (ws, w->screen, paintWindow, wobblyPaintWindow);
    }
    else
    {
	UNWRAP (ws, w->screen, paintWindow);
	status = (*w->screen->paintWindow) (w, attrib, region, mask);
	WRAP (ws, w->screen, paintWindow, wobblyPaintWindow);
    }

    return status;
}

static Bool
wobblyEnableSnapping (CompDisplay     *d,
		      CompAction      *action,
		      CompActionState state,
		      CompOption      *option,
		      int	      nOption)
{
//printf("snapping");
    CompScreen *s;
    CompWindow *w;

    WOBBLY_DISPLAY (d);

    for (s = d->screens; s; s = s->next)
    {
	for (w = s->windows; w; w = w->next)
	{
	    WOBBLY_WINDOW (w);

	    if (ww->grabbed && ww->model)
		modelUpdateSnapping (w, ww->model);
	}
    }

    wd->snapping = TRUE;

    return FALSE;
}

static Bool
wobblyDisableSnapping (CompDisplay     *d,
		       CompAction      *action,
		       CompActionState state,
		       CompOption      *option,
		       int	       nOption)
{
    CompScreen *s;
    CompWindow *w;

    WOBBLY_DISPLAY (d);

    if (!wd->snapping)
	return FALSE;

    for (s = d->screens; s; s = s->next)
    {
	for (w = s->windows; w; w = w->next)
	{
	    WOBBLY_WINDOW (w);

	    if (ww->grabbed && ww->model)
	    {
		if (modelDisableSnapping (w, ww->model))
		{
		    WOBBLY_SCREEN (w->screen);

		    ww->wobbly |= WobblyInitial;
		    ws->wobblyWindows |= ww->wobbly;

		    damagePendingOnScreen (w->screen);
		}
	    }
	}
    }

    wd->snapping = FALSE;

    return FALSE;
}

static Bool
wobblyShiver (CompDisplay     *d,
	      CompAction      *action,
	      CompActionState state,
	      CompOption      *option,
	      int	      nOption)
{
    CompWindow *w;
    Window     xid;

    xid = getIntOptionNamed (option, nOption, "window", 0);

    w = findWindowAtDisplay (d, xid);
    if (w && isWobblyWin (w) && wobblyEnsureModel (w))
    {
	WOBBLY_SCREEN (w->screen);
	WOBBLY_WINDOW (w);

	modelSetMiddleAnchor (ww->model,
			      WIN_X (w), WIN_Y (w),
			      WIN_W (w), WIN_H (w));
	modelAdjustObjectsForShiver (ww->model,
				     WIN_X (w), WIN_Y (w),
				     WIN_W (w), WIN_H (w));

	ww->wobbly |= WobblyInitial;
	ws->wobblyWindows |= ww->wobbly;

	damagePendingOnScreen (w->screen);
    }

    return FALSE;
}

static void
wobblyHandleEvent (CompDisplay *d,
		   XEvent      *event)
{
    Window     activeWindow = 0;
    CompWindow *w;
    CompScreen *s;

    WOBBLY_DISPLAY (d);

    switch (event->type) {
    case PropertyNotify:
	if (event->xproperty.atom == d->winActiveAtom)
	    activeWindow = d->activeWindow;
	break;
    case MapNotify:
	w = findWindowAtDisplay (d, event->xmap.window);
	if (w)
	{
	    WOBBLY_WINDOW (w);

	    if (ww->model)
	    {
		modelInitObjects (ww->model,
				  WIN_X (w), WIN_Y (w), WIN_W (w), WIN_H (w));

		modelInitSprings (ww->model,
				  WIN_X (w), WIN_Y (w), WIN_W (w), WIN_H (w));
	    }
	}
	break;
    default:
	if (event->type == d->xkbEvent)
	{
	    XkbAnyEvent *xkbEvent = (XkbAnyEvent *) event;

	    if (xkbEvent->xkb_type == XkbStateNotify)
	    {
		XkbStateNotifyEvent *stateEvent = (XkbStateNotifyEvent *) event;
		CompAction	    *action;
		unsigned int	    mods = 0xffffffff;

		action = &wd->opt[WOBBLY_DISPLAY_OPTION_SNAP].value.action;

		if (action->type & CompBindingTypeKey)
		    mods = action->key.modifiers;

		if ((stateEvent->mods & mods) == mods )
		    wobblyEnableSnapping (d, NULL, 0, NULL, 0);
		else if ( ! &wd->opt[WOBBLY_DISPLAY_OPTION_DEFAULT_SNAP].value.b )
		    wobblyDisableSnapping (d, NULL, 0, NULL, 0);
	    }
	}
	break;
    }

    UNWRAP (wd, d, handleEvent);
    (*d->handleEvent) (d, event);
    WRAP (wd, d, handleEvent, wobblyHandleEvent);

    switch (event->type) {
    case MotionNotify:
	s = findScreenAtDisplay (d, event->xmotion.root);
	if (s)
	{
	    WOBBLY_SCREEN (s);

	    if (ws->grabWindow			       &&
		(ws->moveWMask & ws->grabWindow->type) &&
		ws->opt[WOBBLY_SCREEN_OPTION_MAXIMIZE_EFFECT].value.b)
	    {
		WOBBLY_WINDOW (ws->grabWindow);

		if (ww->state & MAXIMIZE_STATE)
		{
		    WOBBLY_WINDOW (ws->grabWindow);

		    if (ww->model && ww->grabbed)
		    {
			int dx, dy;

			if (ww->state & CompWindowStateMaximizedHorzMask)
			    dx = pointerX - lastPointerX;
			else
			    dx = 0;

			if (ww->state & CompWindowStateMaximizedVertMask)
			    dy = pointerY - lastPointerY;
			else
			    dy = 0;

			ww->model->anchorObject->position.x += dx;
			ww->model->anchorObject->position.y += dy;

			ww->wobbly |= WobblyInitial;
			ws->wobblyWindows |= ww->wobbly;

			damagePendingOnScreen (s);
		    }
		}
	    }
	}
	break;
    case PropertyNotify:
	if (event->xproperty.atom == d->winActiveAtom)
	{
	    if (d->activeWindow != activeWindow)
	    {
		w = findWindowAtDisplay (d, d->activeWindow);
		if (w && isWobblyWin (w))
		{
		    WOBBLY_WINDOW (w);
		    WOBBLY_SCREEN (w->screen);

		    if ((ws->focusWMask & w->type) &&
			ws->focusEffect		   &&
			wobblyEnsureModel (w))
		    {
			switch (ws->focusEffect) {
			case WobblyEffectShiver:
			    modelAdjustObjectsForShiver (ww->model,
							 WIN_X (w),
							 WIN_Y (w),
							 WIN_W (w),
							 WIN_H (w));
			default:
			    break;
			}
                        
                        ww->friction = ws->opt[WOBBLY_SCREEN_OPTION_FOCUS_FRICTION].value.f;
                        ww->spring_k = ws->opt[WOBBLY_SCREEN_OPTION_FOCUS_SPRING_K].value.f;
                        
			ww->wobbly |= WobblyInitial;
			ws->wobblyWindows |= ww->wobbly;

			damagePendingOnScreen (w->screen);
		    }
		}
	    }
        }
        else if (event->xproperty.atom == wd->wmHintsAtom)
        {
            w = findWindowAtDisplay (d, event->xproperty.window);
            if (w)
            {
                XWMHints *xwmh = XGetWMHints (w->screen->display->display, w->id);
                if (xwmh) 
                {
		    WOBBLY_WINDOW (w);
		    WOBBLY_SCREEN (w->screen);

               	    if (isWobblyWin (w) && (xwmh->flags & XUrgencyHint) && 
                        wobblyEnsureModel (w) && ws->opt[WOBBLY_SCREEN_OPTION_URGENT_EFFECT].value.b)
		    {
    		        Spring *s;
                        int i;
                        float vf;

                        for (i = 0; i < ww->model->numSprings; i++)
                        {
		            s = &ww->model->springs[i];
                            vf = ws->opt[WOBBLY_SCREEN_OPTION_URGENT_VELOCITY].value.f / 30;

                            if (ws->opt[WOBBLY_SCREEN_OPTION_URGENT_IN].value.b)
                            {
			        s->b->velocity.x -= s->offset.x * vf;
			        s->b->velocity.y -= s->offset.y * vf;
			        s->a->velocity.x += s->offset.x * vf;
			        s->a->velocity.y += s->offset.y * vf;
                            }
                            else
                            {
			        s->b->velocity.x += s->offset.x * vf;
			        s->b->velocity.y += s->offset.y * vf;
			        s->a->velocity.x -= s->offset.x * vf;
			        s->a->velocity.y -= s->offset.y * vf;
                            }
		        }

                        if (!ws->opt[WOBBLY_SCREEN_OPTION_URGENT_UNIFORM].value.b)
			    modelSetMiddleAnchor (ww->model, WIN_X (w), WIN_Y (w), WIN_W (w), WIN_H (w));

                        else if (ww->model->anchorObject)
		            ww->model->anchorObject->immobile = FALSE;


			modelAdjustObjectsForShiver (ww->model,
			                             WIN_X (w),
			      		             WIN_Y (w),
				        	     WIN_W (w),
					             WIN_H (w));

                        ww->friction = ws->opt[WOBBLY_SCREEN_OPTION_URGENT_FRICTION].value.f;
                        ww->spring_k = ws->opt[WOBBLY_SCREEN_OPTION_URGENT_SPRING_K].value.f;
                        
			ww->wobbly |= WobblyInitial;
			ws->wobblyWindows |= ww->wobbly;

			damagePendingOnScreen (w->screen);
		        
		    }
                    else
                    {
                        ww->friction = ws->opt[WOBBLY_SCREEN_OPTION_MOVE_FRICTION].value.f;
                        ww->spring_k = ws->opt[WOBBLY_SCREEN_OPTION_MOVE_SPRING_K].value.f;                        
                    }
		XFree(xwmh);
                }
            }
        }
    default:
	break;
    }
}

static Bool
wobblyDamageWindowRect (CompWindow *w,
			Bool	   initial,
			BoxPtr     rect)
{

    Bool status;

    WOBBLY_SCREEN (w->screen);

    if (!initial)
    {
	WOBBLY_WINDOW (w);

	if (ww->wobbly == WobblyForce)
	{
	    REGION region;

	    region.rects = &region.extents;
	    region.numRects = region.size = 1;

	    region.extents.x1 = ww->model->topLeft.x;
	    region.extents.y1 = ww->model->topLeft.y;
	    region.extents.x2 = ww->model->bottomRight.x + 0.5f;
	    region.extents.y2 = ww->model->bottomRight.y + 0.5f;

	    damageScreenRegion (w->screen, &region);

	    return TRUE;
	}
    }

    UNWRAP (ws, w->screen, damageWindowRect);
    status = (*w->screen->damageWindowRect) (w, initial, rect);
    WRAP (ws, w->screen, damageWindowRect, wobblyDamageWindowRect);

    if (initial)
    {
	if (isWobblyWin (w))
	{
	    WOBBLY_WINDOW (w);
	    WOBBLY_SCREEN (w->screen);

	    if (ws->opt[WOBBLY_SCREEN_OPTION_MAXIMIZE_EFFECT].value.b)
		wobblyEnsureModel (w);

	    if ((ws->mapWMask & w->type) &&
		ws->mapEffect		 &&
		wobblyEnsureModel (w))
	    {
		switch (ws->mapEffect) {
		case WobblyEffectShiver:
		    modelAdjustObjectsForShiver (ww->model,
						 WIN_X (w), WIN_Y (w),
						 WIN_W (w), WIN_H (w));
		default:
		    break;
		}

                ww->friction = ws->opt[WOBBLY_SCREEN_OPTION_MAP_FRICTION].value.f;
                ww->spring_k = ws->opt[WOBBLY_SCREEN_OPTION_MAP_SPRING_K].value.f;

                ww->wobbly |= WobblyInitial;
		ws->wobblyWindows |= ww->wobbly;

		damagePendingOnScreen (w->screen);
	    }
	}
    }

    return status;
}

static void
wobblySetWindowScale (CompWindow *w,
		      float      xScale,
		      float      yScale)
{
    WOBBLY_WINDOW (w);
    WOBBLY_SCREEN (w->screen);

    UNWRAP (ws, w->screen, setWindowScale);
    (*w->screen->setWindowScale) (w, xScale, yScale);
    WRAP (ws, w->screen, setWindowScale, wobblySetWindowScale);

    if (wobblyEnsureModel (w))
    {
	if (ww->model->scale.x != xScale ||
	    ww->model->scale.y != yScale)
	{
	    ww->model->scale.x = xScale;
	    ww->model->scale.y = yScale;

	    ww->model->scaleOrigin.x = w->output.left;
	    ww->model->scaleOrigin.y = w->output.top;

	    modelInitObjects (ww->model,
			      WIN_X (w), WIN_Y (w),
			      WIN_W (w), WIN_H (w));

	    modelInitSprings (ww->model,
			      WIN_X (w), WIN_Y (w),
			      WIN_W (w), WIN_H (w));
	}

	if (ww->model->scale.x != 1.0f || ww->model->scale.y != 1.0f)
	    ww->model->transformed = 1;
	else
	    ww->model->transformed = 0;
    }
}

static void
wobblyWindowResizeNotify (CompWindow *w)
{
    WOBBLY_SCREEN (w->screen);
    WOBBLY_WINDOW (w);

    if (ws->opt[WOBBLY_SCREEN_OPTION_MAXIMIZE_EFFECT].value.b &&
	isWobblyWin (w)					      &&
	((w->state ^ ww->state) & MAXIMIZE_STATE))
    {
	if (wobblyEnsureModel (w))
	{
	    if (w->state & MAXIMIZE_STATE)
	    {
		if (!ww->grabbed && ww->model->anchorObject)
		{
		    ww->model->anchorObject->immobile = FALSE;
		    ww->model->anchorObject = NULL;
		}

		modelAddEdgeAnchors (ww->model,
				     WIN_X (w), WIN_Y (w),
				     WIN_W (w), WIN_H (w));
	    }
	    else
	    {
		modelRemoveEdgeAnchors (ww->model,
					WIN_X (w), WIN_Y (w),
					WIN_W (w), WIN_H (w));
		modelSetMiddleAnchor (ww->model,
				      WIN_X (w), WIN_Y (w),
				      WIN_W (w), WIN_H (w));
	    }

	    modelInitSprings (ww->model,
			      WIN_X (w), WIN_Y (w), WIN_W (w), WIN_H (w));

            ww->friction = ws->opt[WOBBLY_SCREEN_OPTION_MAXIMIZE_FRICTION].value.f;
            ww->spring_k = ws->opt[WOBBLY_SCREEN_OPTION_MAXIMIZE_SPRING_K].value.f;

	    ww->wobbly |= WobblyInitial;
	    ws->wobblyWindows |= ww->wobbly;

	    damagePendingOnScreen (w->screen);
	}
    }
    else if (ww->model)
    {
	modelInitObjects (ww->model,
			  WIN_X (w), WIN_Y (w), WIN_W (w), WIN_H (w));

	modelInitSprings (ww->model,
			  WIN_X (w), WIN_Y (w), WIN_W (w), WIN_H (w));
    }

    /* update grab */
    if (ww->model && ww->grabbed)
    {
	if (ww->model->anchorObject)
	    ww->model->anchorObject->immobile = FALSE;

	ww->model->anchorObject = modelFindNearestObject (ww->model,
							  pointerX,
							  pointerY);
	ww->model->anchorObject->immobile = TRUE;

	modelAdjustObjectPosition (ww->model,
				   ww->model->anchorObject,
				   WIN_X (w), WIN_Y (w),
				   WIN_W (w), WIN_H (w));
    }

    ww->state = w->state;

    UNWRAP (ws, w->screen, windowResizeNotify);
    (*w->screen->windowResizeNotify) (w);
    WRAP (ws, w->screen, windowResizeNotify, wobblyWindowResizeNotify);
}

static void
wobblyWindowMoveNotify (CompWindow *w,
			int	   dx,
			int	   dy,
			Bool	   immediate)
{

    WOBBLY_SCREEN (w->screen);
    WOBBLY_WINDOW (w);
    
    if (ww->model)
    {
	if (ww->grabbed && !immediate)
	{
	    if (ww->state & MAXIMIZE_STATE)
	    {
		int i;

		for (i = 0; i < ww->model->numObjects; i++)
		{
		    if (ww->model->objects[i].immobile)
		    {
			ww->model->objects[i].position.x += dx;
			ww->model->objects[i].position.y += dy;
		    }
		}
	    }
	    else
	    {
		ww->model->anchorObject->position.x += dx;
		ww->model->anchorObject->position.y += dy;
	    }

            ww->friction = ws->opt[WOBBLY_SCREEN_OPTION_MOVE_FRICTION].value.f;
            ww->spring_k = ws->opt[WOBBLY_SCREEN_OPTION_MOVE_SPRING_K].value.f;

            ww->wobbly |= WobblyInitial;
	    ws->wobblyWindows |= ww->wobbly;
     
	    damagePendingOnScreen (w->screen);
	}
        else 
        {
	    modelMove (ww->model, dx, dy);

        }

    }
    
    UNWRAP (ws, w->screen, windowMoveNotify);
    (*w->screen->windowMoveNotify) (w, dx, dy, immediate);
    WRAP (ws, w->screen, windowMoveNotify, wobblyWindowMoveNotify);
}

static void
wobblyWindowGrabNotify (CompWindow   *w,
			int	     x,
			int	     y,
			unsigned int state,
			unsigned int mask)
{
//printf("grab");
    WOBBLY_SCREEN (w->screen);
    WOBBLY_DISPLAY(w->screen->display);

    ws->grabMask   = mask;
    ws->grabWindow = w;

    if ((mask & CompWindowGrabButtonMask) &&
	(ws->moveWMask & w->type) &&
	isWobblyWin (w))
    {
	WOBBLY_WINDOW (w);

	if (wobblyEnsureModel (w))
	{
	    Spring *s;
	    int	   i;

	    if (ws->opt[WOBBLY_SCREEN_OPTION_MAXIMIZE_EFFECT].value.b)
	    {
		if (w->state & MAXIMIZE_STATE)
		{
		    modelAddEdgeAnchors (ww->model,
					 WIN_X (w), WIN_Y (w),
					 WIN_W (w), WIN_H (w));
		}
		else
		{
		    modelRemoveEdgeAnchors (ww->model,
					    WIN_X (w), WIN_Y (w),
					    WIN_W (w), WIN_H (w));

		    if (ww->model->anchorObject)
			ww->model->anchorObject->immobile = FALSE;
		}
	    }
	    else
	    {
		if (ww->model->anchorObject)
		    ww->model->anchorObject->immobile = FALSE;
	    }

	    ww->model->anchorObject = modelFindNearestObject (ww->model, x, y);
	    ww->model->anchorObject->immobile = TRUE;

	    ww->grabbed = TRUE;

	    if (mask & CompWindowGrabMoveMask)
	    {
		modelDisableSnapping (w, ww->model);
        if (wd->snapping)
            modelUpdateSnapping (w, ww->model);
        }

	    if (ws->grabWMask & w->type)
	    {
		for (i = 0; i < ww->model->numSprings; i++)
		{
		    s = &ww->model->springs[i];

		    if (s->a == ww->model->anchorObject)
		    {
			s->b->velocity.x -= s->offset.x * 0.05f;
			s->b->velocity.y -= s->offset.y * 0.05f;
		    }
		    else if (s->b == ww->model->anchorObject)
		    {
			s->a->velocity.x += s->offset.x * 0.05f;
			s->a->velocity.y += s->offset.y * 0.05f;
		    }
		}
  
                ww->friction = ws->opt[WOBBLY_SCREEN_OPTION_GRAB_FRICTION].value.f;
                ww->spring_k = ws->opt[WOBBLY_SCREEN_OPTION_GRAB_SPRING_K].value.f;
		
                ww->wobbly |= WobblyInitial;
		ws->wobblyWindows |= ww->wobbly;

		damagePendingOnScreen (w->screen);
	    }
	}
    }

    UNWRAP (ws, w->screen, windowGrabNotify);
    (*w->screen->windowGrabNotify) (w, x, y, state, mask);
    WRAP (ws, w->screen, windowGrabNotify, wobblyWindowGrabNotify);
}

static void
wobblyWindowUngrabNotify (CompWindow *w)
{
    WOBBLY_SCREEN (w->screen);
    WOBBLY_WINDOW (w);

    ws->grabMask   = 0;
    ws->grabWindow = NULL;

    if (ww->grabbed)
    {
	if (ww->model)
	{
	    if (ww->model->anchorObject)
		ww->model->anchorObject->immobile = FALSE;

	    ww->model->anchorObject = NULL;

	    if (ws->opt[WOBBLY_SCREEN_OPTION_MAXIMIZE_EFFECT].value.b)
	    {
		if (ww->state & MAXIMIZE_STATE)
		    modelAddEdgeAnchors (ww->model,
					 WIN_X (w), WIN_Y (w),
					 WIN_W (w), WIN_H (w));
	    }

            if (ws->opt[WOBBLY_SCREEN_OPTION_USE_RELEASE].value.b)
	    {//printf("release");
                ww->friction = ws->opt[WOBBLY_SCREEN_OPTION_RELEASE_FRICTION].value.f;
                ww->spring_k = ws->opt[WOBBLY_SCREEN_OPTION_RELEASE_SPRING_K].value.f;
            } 
		
	    ww->wobbly |= WobblyInitial;
            ws->wobblyWindows |= ww->wobbly;

	    damagePendingOnScreen (w->screen);
	}

	ww->grabbed = FALSE;
    }

    UNWRAP (ws, w->screen, windowUngrabNotify);
    (*w->screen->windowUngrabNotify) (w);
    WRAP (ws, w->screen, windowUngrabNotify, wobblyWindowUngrabNotify);
}


static Bool
wobblyPaintScreen (CompScreen		   *s,
		   const ScreenPaintAttrib *sAttrib,
		   Region		   region,
		   unsigned int		   mask)
{
    Bool status;

    WOBBLY_SCREEN (s);

    if (ws->wobblyWindows)
	mask |= PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS_MASK;

    UNWRAP (ws, s, paintScreen);
    status = (*s->paintScreen) (s, sAttrib, region, mask);
    WRAP (ws, s, paintScreen, wobblyPaintScreen);

    return status;
}

static CompOption *
wobblyGetDisplayOptions (CompDisplay *display,
			 int	     *count)
{
    WOBBLY_DISPLAY (display);

    *count = NUM_OPTIONS (wd);
    return wd->opt;
}

static Bool
wobblySetDisplayOption (CompDisplay     *display,
			char	        *name,
			CompOptionValue *value)
{
    CompOption *o;
    int	       index;

    WOBBLY_DISPLAY (display);

    o = compFindOption (wd->opt, NUM_OPTIONS (wd), name, &index);
    if (!o)
	return FALSE;

    switch (index) {
    case WOBBLY_DISPLAY_OPTION_DEFAULT_SNAP:
	if (compSetBoolOption (o, value))
	{
	    if ( value->b )
		wobblyEnableSnapping (display, NULL, 0, NULL, 0);
	    else
		wobblyDisableSnapping (display, NULL, 0, NULL, 0);
	    return TRUE;
	}
    case WOBBLY_DISPLAY_OPTION_SNAP:
	/* ignore the key */
	value->action.key.keycode = 0;

	if (compSetActionOption (o, value))
	    return TRUE;
	break;
    case WOBBLY_DISPLAY_OPTION_SHIVER:
	if (setDisplayAction (display, o, value))
	    return TRUE;
	break;
    default:
	break;
    }

    return FALSE;
}

static void
wobblyDisplayInitOptions (WobblyDisplay *wd)
{
    CompOption *o;

    o = &wd->opt[WOBBLY_DISPLAY_OPTION_SNAP];
    o->name			  = "snap";
    o->shortDesc		  = N_("Snap windows");
    o->longDesc			  = N_("Toggle window snapping");
    o->type			  = CompOptionTypeAction;
    o->value.action.initiate	  = wobblyEnableSnapping;
    o->value.action.terminate	  = wobblyDisableSnapping;
    o->value.action.bell	  = FALSE;
    o->value.action.edgeMask	  = 0;
    o->value.action.state	  = 0;
    o->value.action.type	  = CompBindingTypeKey;
    o->value.action.key.modifiers = WOBBLY_SNAP_MODIFIERS_DEFAULT;
    o->value.action.key.keycode   = 0;

    o = &wd->opt[WOBBLY_DISPLAY_OPTION_DEFAULT_SNAP];
    o->name	  = "default_snap";
    o->shortDesc  = "Default Snapping to On";
    o->longDesc	  = "Reverse meaning of snapping toggle";
    o->type	  = CompOptionTypeBool;
    o->value.b    = WOBBLY_DEFAULT_SNAP_DEFAULT;

    o = &wd->opt[WOBBLY_DISPLAY_OPTION_SHIVER];
    o->name		      = "shiver";
    o->shortDesc	      = N_("Shiver");
    o->longDesc		      = N_("Make window shiver");
    o->type		      = CompOptionTypeAction;
    o->value.action.initiate  = wobblyShiver;
    o->value.action.terminate = 0;
    o->value.action.bell      = FALSE;
    o->value.action.edgeMask  = 0;
    o->value.action.state     = CompActionStateInitBell;
    o->value.action.state    |= CompActionStateInitKey;
    o->value.action.state    |= CompActionStateInitButton;
    o->value.action.type      = 0;
}

static Bool
wobblyInitDisplay (CompPlugin  *p,
		   CompDisplay *d)
{
    WobblyDisplay *wd;

    wd = malloc (sizeof (WobblyDisplay));
    if (!wd)
	return FALSE;

    wd->screenPrivateIndex = allocateScreenPrivateIndex (d);
    if (wd->screenPrivateIndex < 0)
    {
	free (wd);
	return FALSE;
    }

    wd->wmHintsAtom = XInternAtom (d->display,"WM_HINTS",FALSE);

    WRAP (wd, d, handleEvent, wobblyHandleEvent);

    wd->snapping = FALSE;

    wobblyDisplayInitOptions (wd);

    d->privates[displayPrivateIndex].ptr = wd;

    return TRUE;
}

static void
wobblyFiniDisplay (CompPlugin  *p,
		   CompDisplay *d)
{
    WOBBLY_DISPLAY (d);

    freeScreenPrivateIndex (d, wd->screenPrivateIndex);

    UNWRAP (wd, d, handleEvent);

    free (wd);
}

static Bool
wobblyInitScreen (CompPlugin *p,
		  CompScreen *s)
{
    WobblyScreen *ws;

    WOBBLY_DISPLAY (s->display);

    int i;

    ws = malloc (sizeof (WobblyScreen));
    if (!ws)
	return FALSE;

    ws->windowPrivateIndex = allocateWindowPrivateIndex (s);
    if (ws->windowPrivateIndex < 0)
    {
	free (ws);
	return FALSE;
    }

    ws->wobblyWindows = FALSE;

    ws->mapEffect   = WobblyEffectShiver;
    ws->focusEffect = WobblyEffectNone;

    ws->grabMask   = 0;
    ws->grabWindow = NULL;

    ws->edgeDistance = WOBBLY_EDGE_DISTANCE_DEFAULT;
    ws->edgeVelocity = WOBBLY_EDGE_VELOCITY_DEFAULT;

    wobblyScreenInitOptions (ws, s->display->display);

    /* init the focus effect */
    for (i = 0; i < NUM_EFFECT; i++)
    {
	  if (strcmp (ws->opt[WOBBLY_SCREEN_OPTION_FOCUS_EFFECT].value.s, effectName[i]) == 0)
	  {
	    ws->focusEffect = effectType[i];
	    break;
	  }
    }


    WRAP (ws, s, preparePaintScreen, wobblyPreparePaintScreen);
	printf(" cap ");
	fflush(stdout);
    WRAP (ws, s, donePaintScreen, wobblyDonePaintScreen);
    WRAP (ws, s, paintScreen, wobblyPaintScreen);
    WRAP (ws, s, paintWindow, wobblyPaintWindow);
    WRAP (ws, s, damageWindowRect, wobblyDamageWindowRect);
    WRAP (ws, s, addWindowGeometry, wobblyAddWindowGeometry);
    WRAP (ws, s, drawWindowGeometry, wobblyDrawWindowGeometry);
    WRAP (ws, s, setWindowScale, wobblySetWindowScale);
    WRAP (ws, s, windowResizeNotify, wobblyWindowResizeNotify);
    WRAP (ws, s, windowMoveNotify, wobblyWindowMoveNotify);
    WRAP (ws, s, windowGrabNotify, wobblyWindowGrabNotify);
    WRAP (ws, s, windowUngrabNotify, wobblyWindowUngrabNotify);

    s->privates[wd->screenPrivateIndex].ptr = ws;

    return TRUE;
}

static void
wobblyFiniScreen (CompPlugin *p,
		  CompScreen *s)
{

    
    fflush(stdout);
    WOBBLY_SCREEN (s);

    freeWindowPrivateIndex (s, ws->windowPrivateIndex);

    free (ws->opt[WOBBLY_SCREEN_OPTION_MAP_EFFECT].value.s);
    free (ws->opt[WOBBLY_SCREEN_OPTION_FOCUS_EFFECT].value.s);

    UNWRAP (ws, s, preparePaintScreen);
    UNWRAP (ws, s, donePaintScreen);
    UNWRAP (ws, s, paintScreen);
    UNWRAP (ws, s, paintWindow);
    UNWRAP (ws, s, damageWindowRect);
    UNWRAP (ws, s, addWindowGeometry);
    UNWRAP (ws, s, drawWindowGeometry);
    UNWRAP (ws, s, setWindowScale);
    UNWRAP (ws, s, windowResizeNotify);
    UNWRAP (ws, s, windowMoveNotify);
    UNWRAP (ws, s, windowGrabNotify);
    UNWRAP (ws, s, windowUngrabNotify);

    free (ws);
}

static Bool
wobblyInitWindow (CompPlugin *p,
		  CompWindow *w)
{
    WobblyWindow *ww;

    WOBBLY_SCREEN (w->screen);

    ww = malloc (sizeof (WobblyWindow));
    if (!ww)
	return FALSE;

    ww->model   = 0;
    ww->wobbly  = 0;
    ww->grabbed = FALSE;
    ww->state   = w->state;
    ww->friction = 3.0;
    ww->spring_k = 8.0;

    w->privates[ws->windowPrivateIndex].ptr = ww;

    if (w->mapNum && ws->opt[WOBBLY_SCREEN_OPTION_MAXIMIZE_EFFECT].value.b)
    {
	if (isWobblyWin (w))
	    wobblyEnsureModel (w);
    }

    return TRUE;
}

static void
wobblyFiniWindow (CompPlugin *p,
		  CompWindow *w)
{
    WOBBLY_WINDOW (w);
    
    if (ww->model)
    {
	free (ww->model->objects);
	free (ww->model);
    }

    free (ww);
}

static Bool
wobblyInit (CompPlugin *p)
{
    displayPrivateIndex = allocateDisplayPrivateIndex ();
    if (displayPrivateIndex < 0)
	return FALSE;

    return TRUE;
}

static void
wobblyFini (CompPlugin *p)
{
    if (displayPrivateIndex >= 0)
	freeDisplayPrivateIndex (displayPrivateIndex);
}

CompPluginDep wobblyDeps[] = {
    { CompPluginRuleBefore, "fade" },
    { CompPluginRuleBefore, "cube" },
    { CompPluginRuleBefore, "scale" }
};

CompPluginVTable wobblyVTable = {
    "wobbly",
    N_("Wobbly Windows"),
    N_("Use spring model for wobbly window effect"),
    wobblyInit,
    wobblyFini,
    wobblyInitDisplay,
    wobblyFiniDisplay,
    wobblyInitScreen,
    wobblyFiniScreen,
    wobblyInitWindow,
    wobblyFiniWindow,
    wobblyGetDisplayOptions,
    wobblySetDisplayOption,
    wobblyGetScreenOptions,
    wobblySetScreenOption,
    wobblyDeps,
    sizeof (wobblyDeps) / sizeof (wobblyDeps[0])
};

CompPluginVTable *
getCompPluginInfo (void)
{
    return &wobblyVTable;
}











void getAid getAnUpdatedArrayOfLines(Window window, Line allLinesOnScreen[])
{//PROBLE/PROBLEM // need to restrict to current desktop ie must ignore windows on other desktops/*{{{*/
	       
	       int j = 0;
	i      int i = 0;
        N      Node windowList[1000];
	f      for(i = 0; i < 1000; i++)
	{      {
	       	windowList[i].initialized = 0;
	}      }
	g      getListOfWindows(windowList);	
	i      int allLinesOnScreenCounter = 0;
	/      // go through each window and add its lines to the array of lines
	i      i = 0;	
	w      while(windowList[i].initialized == 1)
	{      {
	       	if(windowList[i].window != window) {
	       	        char* window_name_return;
	                       XFetchName(myDisplay, windowList[i].window, &window_name_return);
	       		printf("  string %s \n", window_name_return);
	       		printf(" MEEE ");
	       		fflush(stdout);
	       		/* translate from the parent window to the root window*/			 
	       		XWindowAttributes win_attr;			
	       		XGetWindowAttributes(myDisplay, windowList[i].window, &win_attr);			
	       		int screen_x, screen_y;		                                                   
	       		Window child_win;			
	       		Window parent_win;                      
	       		Window root_win;			                                                       
	       		Window* child_windows;	
	       		unsigned int num_child_windows;	
	       		XQueryTree(myDisplay, windowList[i].window,
	       		           &root_win,
	       		           &parent_win,
	       		           &child_windows, &num_child_windows);			                                         
	       		XFree(child_windows);
	       		
	       		 /* next, we make the coordinates translation, from the coordinates system 
	       		 of the parent window, to the coordinates system of the root window,    
	       		 which happens to be the same as that of the screen, since the root     
	       		 window always spans the entire screen size.                            
	       		 the 'x' and 'y' values are those previously returned by the            
	       		 XGetWindowAttributes function. */                                        
	       		 XTranslateCoordinates(myDisplay, parent_win, root_win,
	       		                      win_attr.x, win_attr.y, &screen_x, &screen_y,
	       		                      &child_win);
	       		
	       		 /*at this point, screen_x and screen_y contain the location of our original 
	       		 window, using screen coordinates. */
	       		 
	       		 // build and store the 4 lines that are part of this window
	       		 
	       		 int leftXPointWithBorders = screen_x - borderWidth;// 6
	                int upperYPointWithBorders = screen_y - titleBarHeight;//23
	                int rightXPointWithBorders = leftXPointWithBorders + win_attr.width + 2 * borderWidth;//12
	                int bottomYPointWithBorders = upperYPointWithBorders + win_attr.height + titleBarHeight + borderWidth;//29
	       		 
	       		 Line leftXLineWithBorders;
	       		 int x1 = leftXPointWithBorders;
	       		 int y1 = upperYPointWithBorders;
	       		 int x2 = leftXPointWithBorders;
	       		 int y2 = bottomYPointWithBorders;
	       		 double a = y2 - y1;
	       		 double b = x1 - x2;
	       		 double c = (a * x1) + (b * y1);
	       		 leftXLineWithBorders.x1 = x1;
	       		 leftXLineWithBorders.y1 = y1;
	       		 leftXLineWithBorders.x2 = x2;
	       		 leftXLineWithBorders.y2 = y2;
	       		 leftXLineWithBorders.a = a;
	       		 leftXLineWithBorders.b = b;
	       		 leftXLineWithBorders.c = c;
                    leftXLineWithBorders.initialized = TRUE;
	       		 
	       		 Line rightXLineWithBorders;
	       		 x1 = rightXPointWithBorders;
	       		 y1 = upperYPointWithBorders;
	       		 x2 = rightXPointWithBorders;
	       		 y2 = bottomYPointWithBorders;
	       		 a = y2 - y1;
	       		 b = x1 - x2;
	       		 c = (a * x1) + (b * y1);
	       		 rightXLineWithBorders.x1 = x1;
	       		 rightXLineWithBorders.y1 = y1;
	       		 rightXLineWithBorders.x2 = x2;
	       		 rightXLineWithBorders.y2 = y2;
	       		 rightXLineWithBorders.a = a;
	       		 rightXLineWithBorders.b = b;
	       		 rightXLineWithBorders.c = c;    
	       		 rightXLineWithBorders.initialized = TRUE;
	       		 			 
	       		 Line upperYLineWithBorders;
	       		 x1 = leftXPointWithBorders;
	       		 y1 = upperYPointWithBorders;
	       		 x2 = rightXPointWithBorders;
	       		 y2 = upperYPointWithBorders;
	       		 a = y2 - y1;
	       		 b = x1 - x2;
	       		 c = (a * x1) + (b * y1);
	       		 upperYLineWithBorders.x1 = x1;
	       		 upperYLineWithBorders.y1 = y1;
	       		 upperYLineWithBorders.x2 = x2;
	       		 upperYLineWithBorders.y2 = y2;
	       		 upperYLineWithBorders.a = a;
	       		 upperYLineWithBorders.b = b;
	       		 upperYLineWithBorders.c = c;
	       		 upperYLineWithBorders.initialized = TRUE;
	       		 
	       		 
	       		 Line bottomYLineWithBorders;
	       		 x1 = leftXPointWithBorders;
	       		 y1 = bottomYPointWithBorders;
	       		 x2 = rightXPointWithBorders;
	       		 y2 = bottomYPointWithBorders;
	       		 a = y2 - y1;
	       		 b = x1 - x2;
	       		 c = (a * x1) + (b * y1);
	       		 bottomYLineWithBorders.x1 = x1;
	       		 bottomYLineWithBorders.y1 = y1;
	       		 bottomYLineWithBorders.x2 = x2;
	       		 bottomYLineWithBorders.y2 = y2;
	       		 bottomYLineWithBorders.a = a;
	       		 bottomYLineWithBorders.b = b;
	       		 bottomYLineWithBorders.c = c;
	       		 bottomYLineWithBorders.initialized = TRUE;
	                
	                
	                allLinesOnScreen[allLinesOnScreenCounter] = leftXLineWithBorders;
	                allLinesOnScreenCounter++;
	                allLinesOnScreen[allLinesOnScreenCounter] = rightXLineWithBorders;
	                allLinesOnScreenCounter++;
	                allLinesOnScreen[allLinesOnScreenCounter] = upperYLineWithBorders;
	                allLinesOnScreenCounter++;
	                allLinesOnScreen[allLinesOnScreenCounter] = bottomYLineWithBorders;
	                allLinesOnScreenCounter++;
	       	}
	       	i++;
	       	j+=2;
	}      }
	/      // now add the desktop to the grid of lines
    XWind  XWindowAttributes win_attr;			
	X      XGetWindowAttributes(myDisplay, DefaultRootWindow(myDisplay), &win_attr);
	i      int leftXPoint = win_attr.x;
	i      int upperYPoint = win_attr.y;
	i      int rightXPoint = leftXPoint + win_attr.width;
	i      int bottomYPoint = upperYPoint + win_attr.height;
	       
	/      // xLines are lines that are perpendicular to the bottom of the desktop
	L      Line leftXLine;
	i      int x1 = leftXPoint;
	i      int y1 = upperYPoint;
	i      int x2 = leftXPoint;
	i      int y2 = bottomYPoint;
	d      double a = y2 - y1;
	d      double b = x1 - x2;
	d      double c = (a * x1) + (b * y1);
	l      leftXLine.x1 = x1;
	l      leftXLine.y1 = y1;
	l      leftXLine.x2 = x2;
	l      leftXLine.y2 = y2;
	l      leftXLine.a = a;
	l      leftXLine.b = b;
	l      leftXLine.c = c;
	l      leftXLine.initialized = TRUE;
	       		 
	L      Line rightXLine;
	x      x1 = rightXPoint;
	y      y1 = upperYPoint;
	x      x2 = rightXPoint;
	y      y2 = bottomYPoint;
	a      a = y2 - y1;
	b      b = x1 - x2;
	c      c = (a * x1) + (b * y1);
	r      rightXLine.x1 = x1;
	r      rightXLine.y1 = y1;
	r      rightXLine.x2 = x2;
	r      rightXLine.y2 = y2;
	r      rightXLine.a = a;
	r      rightXLine.b = b;
	r      rightXLine.c = c;
	r      rightXLine.initialized = TRUE;
	                             
	       
	/      // yLines are lines that are parallel to the bottom of the desktop
	L      Line upperYLine;
	x      x1 = leftXPoint;
	y      y1 = upperYPoint;
	x      x2 = rightXPoint;
	y      y2 = upperYPoint;
	a      a = y2 - y1;
	b      b = x1 - x2;
	c      c = (a * x1) + (b * y1);
	u      upperYLine.x1 = x1;
	u      upperYLine.y1 = y1;
	u      upperYLine.x2 = x2;
	u      upperYLine.y2 = y2;
	u      upperYLine.a = a;
	u      upperYLine.b = b;
	u      upperYLine.c = c;
	u      upperYLine.initialized = TRUE;
	       		 
	L      Line bottomYLine;
	x      x1 = leftXPoint;
	y      y1 = bottomYPoint;
	x      x2 = rightXPoint;
	y      y2 = bottomYPoint;
	a      a = y2 - y1;
	b      b = x1 - x2;
	c      c = (a * x1) + (b * y1);
	b      bottomYLine.x1 = x1;
	b      bottomYLine.y1 = y1;
	b      bottomYLine.x2 = x2;
	b      bottomYLine.y2 = y2;
	b      bottomYLine.a = a;
	b      bottomYLine.b = b;
	b      bottomYLine.c = c;
	b      bottomYLine.initialized = TRUE;
	       
	a      allLinesOnScreen[allLinesOnScreenCounter] = leftXLine;
	a      allLinesOnScreenCounter++;
	a      allLinesOnScreen[allLinesOnScreenCounter] = rightXLine;
	a      allLinesOnScreenCounter++;
	a      allLinesOnScreen[allLinesOnScreenCounter] = upperYLine;
	a      allLinesOnScreenCounter++;
	a      allLinesOnScreen[allLinesOnScreenCounter] = bottomYLine;
	       
	                
	/      /*allLinesOnScreen.push_back(leftXLine);
	a      allLinesOnScreen.push_back(rightXLine);	
	a      allLinesOnScreen.push_back(upperYLine);
	a      allLinesOnScreen.push_back(bottomYLine);*/

}/*}}}*//*}}}*/

void getAid getAllLinesOfIntersection(Line line, Line linesOfIntersection[], Line allLinesOnScreen[])
{//:PROBL/:PROBLEM // are possible rounding errors here!! /*{{{*/
// we cou we could miss an intersection and then what would happen?
	       	
	/      // go through all the lines and check to see if line
	/      // intersects any of them
	i      int i = 0;
	i      int linesOfIntersectionCounter = 0;
	w      while((long)allLinesOnScreen[i].initialized)
	/      // for(unsigned i = 0; i < allLinesOnScreen.size(); i++)
	{      {
	       	double a1 = line.a;
	       	double a2 = allLinesOnScreen[i].a;
	       	double b1 = line.b;
	       	double b2 = allLinesOnScreen[i].b;
	       	double c1 = line.c;
	       	double c2 = allLinesOnScreen[i].c;
	       	
	       	double det = (a1 * b2) - (a2 * b1);
    	i  	if(det == 0)
    	{  	{
               	//Lines are parallel
    	}  	}
    	e  	else
    	{  	{
    	   		// find the point of intersection
    	   		Line line = allLinesOnScreen[i];
	               double x = ((b2 * c1) - (b1 * c2)) / det;
	               double y = ((a1 * c2) - (a2 * c1)) / det;			
	               
	               // the above point of intersection is for lines not line-segments
	               // so we have to check to see if the point we found
	               // is on one of the line segments
	               // we assume that the line passed to this function
	               // is exteneded to infinity
	               if(       
	                  min(allLinesOnScreen[i].x1, allLinesOnScreen[i].x2) <= x && 
	                  max(allLinesOnScreen[i].x1, allLinesOnScreen[i].x2) >= x &&
	                  min(allLinesOnScreen[i].y1, allLinesOnScreen[i].y2) <= y &&
	                  max(allLinesOnScreen[i].y1, allLinesOnScreen[i].y2) >= y)
	               {	        
	       		   line.xCoordinateOfIntersection = x;
	       		   line.yCoordinateOfIntersection = y;
	       		   linesOfIntersection[linesOfIntersectionCounter] = line;
	       		   linesOfIntersectionCounter++;			   
	               }
    	}  	}
    	i  	i++;	
	}      }	
}/*}}}*//*}}}*/

Line calcne calculateLineOfImpact(Line directionOfThrow, Line allLinesOnScreen[])
{	/      /*{{{*/
	L      
	i      Line linesOfIntersection[ARRAYSIZE];
	f      int i;
	{      for(i = 0; i < ARRAYSIZE; i++)
	       {
	}      	linesOfIntersection[i].initialized = 0;	
	g      }
	       getAllLinesOfIntersection(directionOfThrow, linesOfIntersection, allLinesOnScreen);
	/      
	/      // find the line that got hit by seeing if it went up down left or right, then
	       // searching for the closest intersection point in that direction
	L      
	       Line closestLine;
	/      
	i      // change this. does not need to be a member of closestLine
	// this should be a bool !!!!!!
	i      int foundFirstClosestLine = 0;
	{      // if the line is moving right
	       if(directionOfThrow.x2 > directionOfThrow.x1)
	       {
//	       	int i = 0;
	       	while(linesOfIntersection[i].initialized)
	 		for(unsigned int i = 0; i < linesOfIntersection.size(); i++)
	       	{
	       		if(linesOfIntersection[i].xCoordinateOfIntersection  > directionOfThrow.x2 
	       		   && foundFirstClosestLine == 0)
	       		{
	       			
	       			closestLine = linesOfIntersection[i];
	       			foundFirstClosestLine = 1;
	       			
	       		}
	       		else if(linesOfIntersection[i].xCoordinateOfIntersection > directionOfThrow.x2 &&
	       		        linesOfIntersection[i].xCoordinateOfIntersection < closestLine.xCoordinateOfIntersection)
	       		{
	       			closestLine = linesOfIntersection[i];
	}      			foundFirstClosestLine = 1;
	/      		}
	e      		i++;
	{      	}
	       }
	       // if the line is moving left
//	       else if(directionOfThrow.x2 < directionOfThrow.x1)
	       {
	       	int i = 0;
	       	while(linesOfIntersection[i].initialized)
	 		for(unsigned int i = 0; i < linesOfIntersection.size(); i++)
	       	{
	       		if(linesOfIntersection[i].xCoordinateOfIntersection < directionOfThrow.x2 
	       		   && foundFirstClosestLine == 0)
	       		{
	       			closestLine = linesOfIntersection[i];
	       			foundFirstClosestLine = 1;
	       		}
	       		else if(linesOfIntersection[i].xCoordinateOfIntersection < directionOfThrow.x2 &&
	       		        linesOfIntersection[i].xCoordinateOfIntersection > closestLine.xCoordinateOfIntersection)
	       		{
	       			closestLine = linesOfIntersection[i];
	}      			foundFirstClosestLine = 1;
	/      		}
	e      		i++;
	{      	}
	       }
	       // if the line is moving directly up
//	       else if(directionOfThrow.y2 < directionOfThrow.y1)
	       {
	       	int i = 0;
	       	while(linesOfIntersection[i].initialized)
	 		for(unsigned int i = 0; i < linesOfIntersection.size(); i++)
	       	{
	       		if(linesOfIntersection[i].yCoordinateOfIntersection < directionOfThrow.y2 
	       		   && foundFirstClosestLine == 0)
	       		{
	       			closestLine = linesOfIntersection[i];
	       			foundFirstClosestLine = 1;
	       		}
	       		else if(linesOfIntersection[i].yCoordinateOfIntersection < directionOfThrow.y2 &&
	       		        linesOfIntersection[i].yCoordinateOfIntersection > closestLine.yCoordinateOfIntersection)
	       		{
	       			closestLine = linesOfIntersection[i];
	}      			foundFirstClosestLine = 1;
	/      		}
	e      		i++;
	{      	}
	       }
	       // if the line is moving directly down
//	       else
	       {
	       	int i = 0;
	       	while(linesOfIntersection[i].initialized)
	 		for(unsigned int i = 0; i < linesOfIntersection.size(); i++)
	       	{
	       		if(linesOfIntersection[i].yCoordinateOfIntersection > directionOfThrow.y2 
	       		   && foundFirstClosestLine == 0)
	       		{
	       			closestLine = linesOfIntersection[i];
	       			foundFirstClosestLine = 1;
	       		}
	       		else if(linesOfIntersection[i].yCoordinateOfIntersection > directionOfThrow.y2 &&
	       		        linesOfIntersection[i].yCoordinateOfIntersection < closestLine.yCoordinateOfIntersection)
	       		{
	       			closestLine = linesOfIntersection[i];
	}      			foundFirstClosestLine = 1;
	r      		}
}/*}}}*/       		i++;/*}}}*/
               	}
int scanU      }
{	/      //printf(" xa %f d %i", closestLine.xCoordinateOfIntersection,  directionOfThrow.x2);/*{{{*/
	L      //			fflush(stdout);
	i      
	i      return closestLine;
	w
	/
	{t scanUp(Line line, Line allLinesOnScreen[])
	       
	       Line closestLine;
	       int firstLineFound = 0;
	       int i = 0;
	       while(allLinesOnScreen[i].initialized)
	       // for(unsigned int i = 0; i < allLinesOnScreen.size(); i++)
	       {
	       	if(firstLineFound == 0)		
	       	{
	       		// if horozontal
	       		if(allLinesOnScreen[i].y1 == allLinesOnScreen[i].y2)
	       		{
	       			// if the line is above the start point of the line were scaning up
	       			if(allLinesOnScreen[i].y1 <= line.y1)
	       			{					
	       				// if the line blocks the path of the line we are scanning up
	       				// ie if anypart of the line line overlaps with anypart of the line we are scanning up									
	       				if(allLinesOnScreen[i].x2 > line.x1 && allLinesOnScreen[i].x1 < line.x2)
	       				{
	       					// this could be one line that we want
	       					closestLine = allLinesOnScreen[i];
	       					firstLineFound = 1;
	       				}								
	       			}
	       		}
	       	}
	       	else if(firstLineFound == 1)		
	       	{
	       		// if horozontal
	       		if(allLinesOnScreen[i].y1 == allLinesOnScreen[i].y2)
	       		{
	       			// if the line is above the start point
	       			if(allLinesOnScreen[i].y1 <= line.y1)
	       			{
	       				// if the line blocks the path of the line we are scanning up
	       				// ie if anypart of the line line overlaps with anypart of the line we are scanning up	
	       				if(allLinesOnScreen[i].x2 > line.x1 && allLinesOnScreen[i].x1 < line.x2)
	       				{		
	       					// if this line is closer to the point that got hit 
	       					// than one we allready found
	       					if(allLinesOnScreen[i].y1 > closestLine.y1)
	       					{					
	       						// this could be one line that we want
	}      						closestLine = allLinesOnScreen[i];								
	r      					}																
}/*}}}*/       				}
               			}/*}}}*/
int scanD      		}
{	       	}/*{{{*//*}}}*//*{{{*//*}}}*/
	L      	i++;		
	i      }
	i      return closestLine.y1;
	w
	/
	{t scanDown(Line line, Line allLinesOnScreen[])
	       	
	       Line closestLine;
	       int firstLineFound = 0;
	       int i = 0;
	       while(allLinesOnScreen[i].initialized)
	       // for(unsigned int i = 0; i < allLinesOnScreen.size(); i++)
	       {
	       	if(firstLineFound == 0)		
	       	{
	       		// if horozontal
	       		if(allLinesOnScreen[i].y1 == allLinesOnScreen[i].y2)
	       		{
	       			// if the line is below the start point
	       			if(allLinesOnScreen[i].y1 >= line.y1)
	       			{					
	       				// if the line blocks the path of the line we are scanning down
	       				// ie if anypart of the line line overlaps with anypart of the line we are scanning down									
	       				if(allLinesOnScreen[i].x2 > line.x1 && allLinesOnScreen[i].x1 < line.x2)
	       				{
	       					// this could be one line that we want
	       					closestLine = allLinesOnScreen[i];
	       					firstLineFound = 1;
	       				}								
	       			}
	       		}
	       	}
	       	else if(firstLineFound == 1)		
	       	{
	       		// if horozontal
	       		if(allLinesOnScreen[i].y1 == allLinesOnScreen[i].y2)
	       		{
	       			// if the line is below the start point
	       			if(allLinesOnScreen[i].y1 >= line.y1)
	       			{
	       				// if the line blocks the path of the line we are scanning down
	       				// ie if anypart of the line line overlaps with anypart of the line we are scanning up	
	       				if(allLinesOnScreen[i].x2 > line.x1 && allLinesOnScreen[i].x1 < line.x2)
	       				{		
	       					// if this line is closer to the point that got hit 
	       					// than one we allready found
	       					if(allLinesOnScreen[i].y1 < closestLine.y1)
	       					{					
	       						// this could be one line that we want
	}      						closestLine = allLinesOnScreen[i];								
	r      					}																
}/*}}}*/       				}
               			}
int scanL      		}
{	/      	}
	L      	i++;		
	i      }
	i      return closestLine.y1;
	w
	/
	{t scanLeft(Line line, Line allLinesOnScreen[])
	       
	       Line closestLine;
	       int firstLineFound = 0;
	       int i = 0;
	       while(allLinesOnScreen[i].initialized)
	       // for(unsigned int i = 0; i < allLinesOnScreen.size(); i++)
	       {
	       	if(firstLineFound == 0)		
	       	{
	       		// if vertical
	       		if(allLinesOnScreen[i].x1 == allLinesOnScreen[i].x2)
	       		{
	       			// if the line is Left of the start point
	       			if(allLinesOnScreen[i].x1 <= line.x1)
	       			{					
	       				// if the line blocks the path of the line we are scanning Left
	       				// ie if anypart of the line line overlaps with anypart of the line we are scanning up									
	       				if(allLinesOnScreen[i].y2 > line.y1 && allLinesOnScreen[i].y1 < line.y2)
	       				{
	       					// this could be one line that we want
	       					closestLine = allLinesOnScreen[i];
	       					//firstLineFound = 1;
	       				}								
	       			}
	       		}
	       	}
	       	else if(firstLineFound == 1)		
	       	{
	       		// if vertical
	       		if(allLinesOnScreen[i].x1 == allLinesOnScreen[i].x2)
	       		{
	       			// if the line is left the start point
	       			if(allLinesOnScreen[i].x1 <= line.x1)
	       			{
	       				// if the line blocks the path of the line we are scanning left
	       				// ie if anypart of the line line overlaps with anypart of the line we are scanning up	
	       				if(allLinesOnScreen[i].y2 > line.y1 && allLinesOnScreen[i].y1 < line.y2)
	       				{		
	       					// if this line is closer to the point that got hit 
	       					// than one we allready found
	       					if(allLinesOnScreen[i].x1 > closestLine.x1)
	       					{					
	       						// this could be one line that we want
	}      						closestLine = allLinesOnScreen[i];								
	r      					}																
}/*}}}*/       				}
               			}
int scanR      		}
{	/      	}
	L      	i++;	
	i      }
	i      return closestLine.x1;
	w
//	f
	{t scanRight(Line line, Line allLinesOnScreen[])
	       
	       Line closestLine;
	       int firstLineFound = 0;
	       int i = 0;
	       while(allLinesOnScreen[i].initialized)
	 	for(unsigned int i = 0; i < allLinesOnScreen.size(); i++)
	       {
	       	if(firstLineFound == 0)		
	       	{
	       		// if vertical
	       		if(allLinesOnScreen[i].x1 == allLinesOnScreen[i].x2)
	       		{
	       			// if the line is Right of the start point
	       			if(allLinesOnScreen[i].x1 >= line.x1)
	       			{					
	       				// if the line blocks the path of the line we are scanning Right
	       				// ie if anypart of the line line overlaps with anypart of the line we are scanning up									
	       				if(allLinesOnScreen[i].y2 > line.y1 && allLinesOnScreen[i].y1 < line.y2)
	       				{
	       					// this could be one line that we want
	       					closestLine = allLinesOnScreen[i];
	       					//firstLineFound = 1;
	       				}								
	       			}
	       		}
	       	}
	       	else if(firstLineFound == 1)		
	       	{
	       		// if vertical
	       		if(allLinesOnScreen[i].x1 == allLinesOnScreen[i].x2)
	       		{
	       			// if the line is Right the start point
	       			if(allLinesOnScreen[i].x1 >= line.x1)
	       			{
	       				// if the line blocks the path of the line we are scanning Right
	       				// ie if anypart of the line line overlaps with anypart of the line we are scanning up	
	       				if(allLinesOnScreen[i].y2 > line.y1 && allLinesOnScreen[i].y1 < line.y2)
	       				{		
	       					// if this line is closer to the point that got hit 
	       					// than one we allready found
	       					if(allLinesOnScreen[i].x1 < closestLine.x1)
	       					{					
	       						// this could be one line that we want
	       						closestLine = allLinesOnScreen[i];								
	       					}																
	}      				}
	r      			}
}/*}}}*/       		}
               	}
void calc      	i++;		
{/*{{{*/       }
	/      return closestLine.x1;
	L
	g
	/id calculateDimensionsGivenVerticalLineHitFromLeft( int xHitCoordinate, int yHitCoordinate, ValidWindowExpansion validWindowExpansions[], Window window)
	i      
	i      // get all the lines on screen
	w      Line allLinesOnScreen[ARRAYSIZE];	
	/      getAnUpdatedArrayOfLines(window, allLinesOnScreen);
	{      // for each line
	       int i = 0;
	       int validWindowExpansionsCounter = 0;
	       while(allLinesOnScreen[i].initialized)
	       // for(unsigned int i = 0; i < allLinesOnScreen.size(); i++)
	       {
	       	// if the ith line is vertical ie parallel to the line that got hit
	       	// and to the left of it
	       	if(allLinesOnScreen[i].x1 == allLinesOnScreen[i].x2 
	       	   && allLinesOnScreen[i].x1 < xHitCoordinate)
	       	{
	       		// throw an imaginary line away from the point that got 
	       		// hit and if it hits anything before getting the x 
	       		// coordinate of this vertical line
	       		// we know we should not consider this line						
	       							
	       		Line throwLeft;					
	       		throwLeft.x2 = xHitCoordinate - 1;
	       		throwLeft.y2 = yHitCoordinate;
               		throwLeft.x1 = xHitCoordinate;
	       		throwLeft.y1 = yHitCoordinate;
	       		throwLeft.a = throwLeft.y2 - throwLeft.y1;
	       	    throwLeft.b = throwLeft.x1 - throwLeft.x2;
	       	    throwLeft.c = (throwLeft.a * throwLeft.x1) + (throwLeft.b * throwLeft.y1);
	           Line firstLineHitToLeft = calculateLineOfImpact(throwLeft, allLinesOnScreen);
	       				
	       		// if the first vertical line to get hit is
	       		// the ith vertical line or is farther from the point that
	       		// got hit than the ith vertical line then this vertical line
	       	    // marks the left side of a valid window expansion
	       		if(firstLineHitToLeft.x1 <= allLinesOnScreen[i].x1)
	       		{
	       			// create the line to scan up and down
	       			Line verticalScanLine;
	       			verticalScanLine.x1 = firstLineHitToLeft.xCoordinateOfIntersection;
	       			verticalScanLine.y1 = firstLineHitToLeft.yCoordinateOfIntersection;
	       			verticalScanLine.x2 = xHitCoordinate;
	       			verticalScanLine.y2 = yHitCoordinate;
	       			verticalScanLine.a = verticalScanLine.y2 - verticalScanLine.y1;
	       			verticalScanLine.b = verticalScanLine.x1 - verticalScanLine.x2;
	       			verticalScanLine.c = (verticalScanLine.a * verticalScanLine.x1) + (verticalScanLine.b * verticalScanLine.y1);
	       			// now scan up scan down and scan left
	       			int upperYBorder = scanUp(verticalScanLine, allLinesOnScreen);
	       			int lowerYBorder = scanDown(verticalScanLine, allLinesOnScreen);
	       			// create a horozontal scan line
	       			Line horozontalScanLine;
	       			// x1 need to be twards the top of the screen
	       			horozontalScanLine.x1 = allLinesOnScreen[i].x1;
	       			horozontalScanLine.y1 = upperYBorder;
	       		    horozontalScanLine.x2 = allLinesOnScreen[i].x1;
	       			horozontalScanLine.y2 = lowerYBorder;
	       			horozontalScanLine.a = horozontalScanLine.y2 - horozontalScanLine.y1;
	       			horozontalScanLine.b = horozontalScanLine.x1 - horozontalScanLine.x2;
	       			horozontalScanLine.c = (horozontalScanLine.a * horozontalScanLine.x1) + (horozontalScanLine.b * horozontalScanLine.y1);
	       			int leftXBorder = scanLeft(horozontalScanLine, allLinesOnScreen);
	       			
	       			ValidWindowExpansion validWindowExpansion;
	       			validWindowExpansion.x = leftXBorder;
	       			validWindowExpansion.y = upperYBorder;
	       			validWindowExpansion.height = lowerYBorder - upperYBorder;
	       			validWindowExpansion.width = xHitCoordinate - leftXBorder;
	       			validWindowExpansion.initialized = 1;	    
	}      			validWindowExpansions[validWindowExpansionsCounter] = validWindowExpansion;
}/*}}}*/       			validWindowExpansionsCounter++;
               		}				
void calc      	}
{/*{{{*/       	i++;
	       }	
	L
	g
	/id calculateDimensionsGivenVerticalLineHitFromRight(int xHitCoordinate, int yHitCoordinate, ValidWindowExpansion validWindowExpansions[], Window window)
	/
	i      // get all the lines on screen
	i      Line allLinesOnScreen[ARRAYSIZE];	
	w      getAnUpdatedArrayOfLines(window, allLinesOnScreen);
//	f      // for each line
	{      int i = 0;
	       int validWindowExpansionsCounter = 0;
	       while(allLinesOnScreen[i].initialized)
	 	for(unsigned int i = 0; i < allLinesOnScreen.size(); i++)
   	       {
	 
	       	// if the ith line is vertical ie parallel to the line that got hit and 
	       	// to the right of it
	       	if(allLinesOnScreen[i].x1 == allLinesOnScreen[i].x2
	  		   && allLinesOnScreen[i].x1 > xHitCoordinate)
	       	{
	       		// throw an imaginary line away from the point that got 
	       		// hit and if it hits anything before getting the x 
	       		// coordinate of this vertical line
	       		// we know we should not consider this line	
	       		Line throwRight;					
	       		throwRight.x2 = xHitCoordinate + 1;
	       		throwRight.y2 = yHitCoordinate;
	       		throwRight.x1 = xHitCoordinate;
	       		throwRight.y1 = yHitCoordinate;
	       		throwRight.a = throwRight.y2 - throwRight.y1;
	       	        throwRight.b = throwRight.x1 - throwRight.x2;
	       	        throwRight.c = (throwRight.a * throwRight.x1) + (throwRight.b * throwRight.y1);
	       		Line firstLineHitToRight = calculateLineOfImpact(throwRight, allLinesOnScreen);
	       		///printf(" first hit to right x %i ", firstLineHitToRight.xCoordinateOfIntersection);
	       		//fflush(stdout);
	       		
	       		// if the first vertical line to get hit is
	       		// the ith vertical line or is farther from the point that
	       		// got hit than the ith vertical line then this vertical line
	       		// MAY mark the left side of the window expansion
	       		if(firstLineHitToRight.x1 >= allLinesOnScreen[i].x1)
	       		{
	       			// create the line to scan up and down
	       			Line verticalScanLine;
	       			verticalScanLine.x1 = xHitCoordinate;
	       			verticalScanLine.y1 = yHitCoordinate;
	       			verticalScanLine.x2 = firstLineHitToRight.xCoordinateOfIntersection;
	       			verticalScanLine.y2 = firstLineHitToRight.yCoordinateOfIntersection;
	       			verticalScanLine.a = verticalScanLine.y2 - verticalScanLine.y1;
	       			verticalScanLine.b = verticalScanLine.x1 - verticalScanLine.x2;
	       			verticalScanLine.c = (verticalScanLine.a * verticalScanLine.x1) + (verticalScanLine.b * verticalScanLine.y1);
	       			// now scan up scan down and scan left
	       			int upperYBorder = scanUp(verticalScanLine, allLinesOnScreen);
	       			int lowerYBorder = scanDown(verticalScanLine, allLinesOnScreen);
	       			
	       			//printf(" point hit to right %i \n upper %i \n lower %i \n", firstLineHitToRight.x2, upperYBorder, lowerYBorder);
	       			fflush(stdout);
	       			// create a horozontal scan line
	       			Line horozontalScanLine;
	       			// x1 need to be twards the top of the screen
	       			horozontalScanLine.x1 = allLinesOnScreen[i].x1;
	       			horozontalScanLine.y1 = upperYBorder;
	       		        horozontalScanLine.x2 = allLinesOnScreen[i].x1;
	       			horozontalScanLine.y2 = lowerYBorder;
	       			horozontalScanLine.a = horozontalScanLine.y2 - horozontalScanLine.y1;
	       			horozontalScanLine.b = horozontalScanLine.x1 - horozontalScanLine.x2;
	       			horozontalScanLine.c = (horozontalScanLine.a * horozontalScanLine.x1) + (horozontalScanLine.b * horozontalScanLine.y1);
	       			int rightXBorder = scanRight(horozontalScanLine, allLinesOnScreen);
	       			
	       			
	       			ValidWindowExpansion validWindowExpansion;
	       			validWindowExpansion.x = xHitCoordinate;
	}      			validWindowExpansion.y = upperYBorder;
}/*}}}*/       			validWindowExpansion.height = lowerYBorder - upperYBorder;
               			validWindowExpansion.width = rightXBorder - xHitCoordinate;
void calc      			validWindowExpansion.initialized = 1;			    
{	/      			validWindowExpansions[validWindowExpansionsCounter] = validWindowExpansion;
	L      			validWindowExpansionsCounter++;
	g      		}
	/      	}
	/      	i++;
	i      }	
	i
	w
//	fid calculateDimensionsGivenHorozontalLineHitFromBottom(int xHitCoordinate, int yHitCoordinate, ValidWindowExpansion validWindowExpansions[], Window window)
	{      
	       // get all the lines on screen
	       Line allLinesOnScreen[ARRAYSIZE];	
	       getAnUpdatedArrayOfLines(window, allLinesOnScreen);
   	       // for each line
	       int i = 0;
	       int validWindowExpansionsCounter = 0;
	       while(allLinesOnScreen[i].initialized)
	 	for(unsigned int i = 0; i < allLinesOnScreen.size(); i++)
	       {
	       	// if the ith line is horozontal ie parallel to the line that got hit and 
	       	// is below the line that got hit
	       	if(allLinesOnScreen[i].y1 == allLinesOnScreen[i].y2
	  		   && allLinesOnScreen[i].y1 > yHitCoordinate)
	       	{
	       		
	       		Line throwDown;					
	       		throwDown.x2 = xHitCoordinate;
	       		throwDown.y2 = yHitCoordinate + 1;
	       		throwDown.x1 = xHitCoordinate;
	       		throwDown.y1 = yHitCoordinate;
	       		throwDown.a = throwDown.y2 - throwDown.y1;
	       	    throwDown.b = throwDown.x1 - throwDown.x2;
	       	    throwDown.c = (throwDown.a * throwDown.x1) + (throwDown.b * throwDown.y1);
	       		Line firstLineHitToBottom = calculateLineOfImpact(throwDown, allLinesOnScreen);
	       				
	       		// throw an imaginary line away from the point that got 
	       		// hit and if it hits anything before getting the y 
	       		// coordinate of this horozontal line
	       		// we know we should not consider this line	
	       		if(firstLineHitToBottom.y1 <= allLinesOnScreen[i].y1)
	       		{
	       			// create a horozontal scan line
	       			Line horozontalScanLine;
	       			// x1 need to be twards the top of the screen
	       			horozontalScanLine.x1 = xHitCoordinate;
	       			// need these 1s to make sure we dont hit the lines we scann from
	       			horozontalScanLine.y1 = yHitCoordinate + 1;
	       		    horozontalScanLine.x2 = firstLineHitToBottom.xCoordinateOfIntersection;
	       			horozontalScanLine.y2 = firstLineHitToBottom.yCoordinateOfIntersection - 1;
	       			horozontalScanLine.a = horozontalScanLine.y2 - horozontalScanLine.y1;
	       			horozontalScanLine.b = horozontalScanLine.x1 - horozontalScanLine.x2;
	       			horozontalScanLine.c = (horozontalScanLine.a * horozontalScanLine.x1) + (horozontalScanLine.b * horozontalScanLine.y1);
	       			int rightXBorder = scanRight(horozontalScanLine, allLinesOnScreen);
	       			int leftXBorder = scanLeft(horozontalScanLine, allLinesOnScreen);
	       			
	       			// create the line to scan down
	       			Line verticalScanLine;
	       			verticalScanLine.x1 = leftXBorder;
	       			// need the + 1 to make sure we dont hit the line we scann from
	       			verticalScanLine.y1 = yHitCoordinate + 1;
	       			verticalScanLine.x2 = rightXBorder;
	       			verticalScanLine.y2 = yHitCoordinate + 1;
	       			verticalScanLine.a = verticalScanLine.y2 - verticalScanLine.y1;
	       			verticalScanLine.b = verticalScanLine.x1 - verticalScanLine.x2;
	       			verticalScanLine.c = (verticalScanLine.a * verticalScanLine.x1) + (verticalScanLine.b * verticalScanLine.y1);
	       			// now scan up scan down and scan left				
	       			int lowerYBorder = scanDown(verticalScanLine, allLinesOnScreen);				
	       			
	       			ValidWindowExpansion validWindowExpansion;
	       			validWindowExpansion.x = leftXBorder;
	}      			validWindowExpansion.y = yHitCoordinate;
}/*}}}*/       			validWindowExpansion.height = lowerYBorder - yHitCoordinate;
               			validWindowExpansion.width = rightXBorder - leftXBorder;
void calc      			validWindowExpansion.initialized = 1;		    
{	/      			validWindowExpansions[validWindowExpansionsCounter] = validWindowExpansion;
	L      			validWindowExpansionsCounter++;
	g      		}
	/      	}
	i      	i++;
	i      }	
	w
	{
	 id calculateDimensionsGivenHorozontalLineHitFromTop(int xHitCoordinate, int yHitCoordinate, ValidWindowExpansion validWindowExpansions[], Window window)
	       
	       // get all the lines on screen
   	       Line allLinesOnScreen[ARRAYSIZE];	
	       getAnUpdatedArrayOfLines(window, allLinesOnScreen);
	       // for each line
	       int i = 0;
	       int validWindowExpansionsCounter = 0;
	       while(allLinesOnScreen[i].initialized)
	 	for(unsigned int i = 0; i < allLinesOnScreen.size(); i++)
	       {
	       	// if the ith line is horozontal ie parallel to the line that got hit and 
	       	// is above the line that got hit
	       	if(allLinesOnScreen[i].y1 == allLinesOnScreen[i].y2
	  		   && allLinesOnScreen[i].y1 < yHitCoordinate)
	       	{
	       		
	       		Line throwUp;					
	       		throwUp.x2 = xHitCoordinate;
	       		throwUp.y2 = yHitCoordinate - 1;
	       		throwUp.x1 = xHitCoordinate;
	       		throwUp.y1 = yHitCoordinate;
	       		throwUp.a = throwUp.y2 - throwUp.y1;
	       	    throwUp.b = throwUp.x1 - throwUp.x2;
	       	    throwUp.c = (throwUp.a * throwUp.x1) + (throwUp.b * throwUp.y1);
	       		Line firstLineHitToTop = calculateLineOfImpact(throwUp, allLinesOnScreen);
	       				
	       		// throw an imaginary line away from the point that got 
	       		// hit and if it hits anything before getting the y 
	       		// coordinate of this horozontal line
	       		// we know we should not consider this line	
	       		if(firstLineHitToTop.y1 >= allLinesOnScreen[i].y1)
	       		{
	       			// create a horozontal scan line
	       			Line horozontalScanLine;
	       			// x1 need to be twards the top of the screen
	       			horozontalScanLine.x1 = firstLineHitToTop.xCoordinateOfIntersection; 
	       			// need these 1s to make sure we dont hit the lines we scann from
	       			horozontalScanLine.y1 = firstLineHitToTop.yCoordinateOfIntersection + 1;
	       		    horozontalScanLine.x2 = xHitCoordinate;
	       			horozontalScanLine.y2 = yHitCoordinate - 1;
	       			horozontalScanLine.a = horozontalScanLine.y2 - horozontalScanLine.y1;
	       			horozontalScanLine.b = horozontalScanLine.x1 - horozontalScanLine.x2;
	       			horozontalScanLine.c = (horozontalScanLine.a * horozontalScanLine.x1) + (horozontalScanLine.b * horozontalScanLine.y1);
	       			int rightXBorder = scanRight(horozontalScanLine, allLinesOnScreen);
	       			int leftXBorder = scanLeft(horozontalScanLine, allLinesOnScreen);
	       			
	       			// create the line to scan down
	       			Line verticalScanLine;
	       			verticalScanLine.x1 = leftXBorder;
	       			// need the + 1 to make sure we dont hit the line we scann from
	       			verticalScanLine.y1 = yHitCoordinate - 1;
	       			verticalScanLine.x2 = rightXBorder;
	       			verticalScanLine.y2 = yHitCoordinate - 1;
	       			verticalScanLine.a = verticalScanLine.y2 - verticalScanLine.y1;
	       			verticalScanLine.b = verticalScanLine.x1 - verticalScanLine.x2;
	       			verticalScanLine.c = (verticalScanLine.a * verticalScanLine.x1) + (verticalScanLine.b * verticalScanLine.y1);
	       			// now scan up scan down and scan left				
	       			int upperYBorder = scanUp(verticalScanLine, allLinesOnScreen);				
	       			
	}      			ValidWindowExpansion validWindowExpansion;
}/*}}}*/       			validWindowExpansion.x = leftXBorder;
               			validWindowExpansion.y = upperYBorder;
void getL      			validWindowExpansion.height = yHitCoordinate - upperYBorder;
{// probl      			validWindowExpansion.width = rightXBorder - leftXBorder;
// what e      			validWindowExpansion.initialized = 1;	
    Atom       			validWindowExpansions[validWindowExpansionsCounter] = validWindowExpansion;
    int a      			validWindowExpansionsCounter++;			
    unsig      		}
    unsig      	}
	X      	i++;		
	       }	
	 
	 
	W
	lid getListOfWindows(Node windowList[])
	i/ problem: icons are also widnows on a desktop
	u what else could be a window?	
    for (  Atom actual_type;
    {      int actual_format;    
    	/  unsigned long nitems, bytes_after;
        /  unsigned char *prop;
        A      XGetWindowProperty(myDisplay, DefaultRootWindow(myDisplay),
	       				   XInternAtom(myDisplay, "_NET_CLIENT_LIST", TRUE),
	       				   0L, 100000, FALSE, AnyPropertyType, &actual_type,
	       				   &actual_format, &nitems, &bytes_after, &prop);
	       Window* list;
	       list = (Window*) prop;	
	       int windowListCount = 0;
	       unsigned int i;
	       
	       fflush(stdout);
	   for (i = 0; i < nitems; i++)
	   {
	   	//*****************get the window type
	       //Atom windowType = getWindowType(list[i]);
	           Atom windowType = None;
	           Atom actual_type;
	           int actual_format;
	           unsigned long nitems, bytes_after;
        c          unsigned char *prop_return = NULL;	    
        X          
        /          if(Success == XGetWindowProperty(myDisplay, list[i],
        /          	                             XInternAtom(myDisplay, "_NET_WM_WINDOW_TYPE", False),
        /          	                             0L, sizeof(Atom),
        /                                           False, AnyPropertyType, &actual_type,
        i                                           &actual_format, &nitems, &bytes_after,
        {                                           &prop_return) && prop_return)
                   {
                       windowType = *(Atom *)prop_return;
                       XFree(prop_return);
	           }
	           //**************
	       //printf("1");
	       fflush(stdout);
	       char* window_name_return;
	       XFetchName(myDisplay, list[i], &window_name_return);
	       // try to include the desktop later to avoid duplicate code
	       //if(windowType != XInternAtom(display, "_NET_WM_WINDOW_TYPE_DESKTOP", FALSE)
	       //&& windowType != XInternAtom(display, "_NET_WM_WINDOW_TYPE_DOCK", FALSE)
	       //&& window_name_return)
	       if(windowType == XInternAtom(myDisplay, "_NET_WM_WINDOW_TYPE_NORMAL", FALSE))
	       {
	       	//string name = new string(window_name_return);
               	if(window_name_return[0] != 'c')    	
       	}      	{        	
    }                  	//XWindowAttributes* att;
}/*}}}*/               	//XGetWindowAttributes(display, list[i], att);
              	
              	windowList[windowListCount].window = list[i];
      		windowList[windowListCount].initialized = 1;
              	windowListCount++;
              	
              	
              	//printf("%s",window_name_return);
              	
             		//cout << "\n";	 		
      	       	//fflush(stdout);
      	}
     	}         
  }   


int max(int x, int y)
{
    if (x >= y)
    {
        return x;
    }
    return y;
}

int min(int x, int y)
{
    if (x <= y)
    {
        return x;
    }
    return y;
}
/*
Atom getWindowType(Window win)
{
    Atom window_type = None;
    Atom actual_type;
    int actual_format;
    unsigned long nitems, bytes_after;
    unsigned char *prop_return = NULL;
    
    Display* display = XOpenDisplay(0);
    if(Success == XGetWindowProperty(display, win,
    								 XInternAtom(display, "_NET_WM_WINDOW_TYPE", False),
    								 0L, sizeof(Atom),
                                     False, AnyPropertyType, &actual_type,
                                     &actual_format, &nitems, &bytes_after,
                                     &prop_return) && prop_return)
    {
        window_type = *(Atom *)prop_return;
        XFree(prop_return);
    }    
    return window_type;
}*/
